1ac1dc6b2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 266aee900SScott Liu /* 366aee900SScott Liu * Elan Microelectronics touch panels with I2C interface 466aee900SScott Liu * 566aee900SScott Liu * Copyright (C) 2014 Elan Microelectronics Corporation. 666aee900SScott Liu * Scott Liu <scott.liu@emc.com.tw> 766aee900SScott Liu * 866aee900SScott Liu * This code is partly based on hid-multitouch.c: 966aee900SScott Liu * 1066aee900SScott Liu * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> 1166aee900SScott Liu * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> 1266aee900SScott Liu * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France 1366aee900SScott Liu * 1466aee900SScott Liu * This code is partly based on i2c-hid.c: 1566aee900SScott Liu * 1666aee900SScott Liu * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> 1766aee900SScott Liu * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France 1866aee900SScott Liu * Copyright (c) 2012 Red Hat, Inc 1966aee900SScott Liu */ 2066aee900SScott Liu 2166aee900SScott Liu 22f27ad893SJohnny Chuang #include <linux/bits.h> 2366aee900SScott Liu #include <linux/module.h> 2466aee900SScott Liu #include <linux/input.h> 2566aee900SScott Liu #include <linux/interrupt.h> 264c83c071SDmitry Torokhov #include <linux/irq.h> 2766aee900SScott Liu #include <linux/platform_device.h> 2866aee900SScott Liu #include <linux/async.h> 2966aee900SScott Liu #include <linux/i2c.h> 3066aee900SScott Liu #include <linux/delay.h> 3166aee900SScott Liu #include <linux/uaccess.h> 3266aee900SScott Liu #include <linux/buffer_head.h> 3366aee900SScott Liu #include <linux/slab.h> 3466aee900SScott Liu #include <linux/firmware.h> 3566aee900SScott Liu #include <linux/input/mt.h> 3668334dbaSMichał Mirosław #include <linux/input/touchscreen.h> 3766aee900SScott Liu #include <linux/acpi.h> 3866aee900SScott Liu #include <linux/of.h> 39*2e758f53SRaul E Rangel #include <linux/pm_wakeirq.h> 40afe10358SDmitry Torokhov #include <linux/gpio/consumer.h> 41afe10358SDmitry Torokhov #include <linux/regulator/consumer.h> 4265299e8bSHans de Goede #include <linux/uuid.h> 4366aee900SScott Liu #include <asm/unaligned.h> 4466aee900SScott Liu 4566aee900SScott Liu /* Device, Driver information */ 4666aee900SScott Liu #define DEVICE_NAME "elants_i2c" 4766aee900SScott Liu 4866aee900SScott Liu /* Convert from rows or columns into resolution */ 4966aee900SScott Liu #define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) 5066aee900SScott Liu 5166aee900SScott Liu /* FW header data */ 5266aee900SScott Liu #define HEADER_SIZE 4 5366aee900SScott Liu #define FW_HDR_TYPE 0 5466aee900SScott Liu #define FW_HDR_COUNT 1 5566aee900SScott Liu #define FW_HDR_LENGTH 2 5666aee900SScott Liu 5766aee900SScott Liu /* Buffer mode Queue Header information */ 5866aee900SScott Liu #define QUEUE_HEADER_SINGLE 0x62 5966aee900SScott Liu #define QUEUE_HEADER_NORMAL 0X63 6066aee900SScott Liu #define QUEUE_HEADER_WAIT 0x64 619517b95bSMichał Mirosław #define QUEUE_HEADER_NORMAL2 0x66 6266aee900SScott Liu 6366aee900SScott Liu /* Command header definition */ 6466aee900SScott Liu #define CMD_HEADER_WRITE 0x54 6566aee900SScott Liu #define CMD_HEADER_READ 0x53 6666aee900SScott Liu #define CMD_HEADER_6B_READ 0x5B 67f0b57e19SJohnny.Chuang #define CMD_HEADER_ROM_READ 0x96 6866aee900SScott Liu #define CMD_HEADER_RESP 0x52 6966aee900SScott Liu #define CMD_HEADER_6B_RESP 0x9B 70f0b57e19SJohnny.Chuang #define CMD_HEADER_ROM_RESP 0x95 7166aee900SScott Liu #define CMD_HEADER_HELLO 0x55 7266aee900SScott Liu #define CMD_HEADER_REK 0x66 7366aee900SScott Liu 7466aee900SScott Liu /* FW position data */ 759517b95bSMichał Mirosław #define PACKET_SIZE_OLD 40 7666aee900SScott Liu #define PACKET_SIZE 55 7766aee900SScott Liu #define MAX_CONTACT_NUM 10 7866aee900SScott Liu #define FW_POS_HEADER 0 7966aee900SScott Liu #define FW_POS_STATE 1 8066aee900SScott Liu #define FW_POS_TOTAL 2 8166aee900SScott Liu #define FW_POS_XY 3 82f27ad893SJohnny Chuang #define FW_POS_TOOL_TYPE 33 8366aee900SScott Liu #define FW_POS_CHECKSUM 34 8466aee900SScott Liu #define FW_POS_WIDTH 35 8566aee900SScott Liu #define FW_POS_PRESSURE 45 8666aee900SScott Liu 8766aee900SScott Liu #define HEADER_REPORT_10_FINGER 0x62 8866aee900SScott Liu 89c18b443cSMichał Mirosław /* Header (4 bytes) plus 3 full 10-finger packets */ 9066aee900SScott Liu #define MAX_PACKET_SIZE 169 9166aee900SScott Liu 9266aee900SScott Liu #define BOOT_TIME_DELAY_MS 50 9366aee900SScott Liu 9466aee900SScott Liu /* FW read command, 0x53 0x?? 0x0, 0x01 */ 9566aee900SScott Liu #define E_ELAN_INFO_FW_VER 0x00 9666aee900SScott Liu #define E_ELAN_INFO_BC_VER 0x10 979517b95bSMichał Mirosław #define E_ELAN_INFO_X_RES 0x60 989517b95bSMichał Mirosław #define E_ELAN_INFO_Y_RES 0x63 9993f63406SJohnny Chuang #define E_ELAN_INFO_REK 0xD0 10066aee900SScott Liu #define E_ELAN_INFO_TEST_VER 0xE0 10166aee900SScott Liu #define E_ELAN_INFO_FW_ID 0xF0 10266aee900SScott Liu #define E_INFO_OSR 0xD6 10366aee900SScott Liu #define E_INFO_PHY_SCAN 0xD7 10466aee900SScott Liu #define E_INFO_PHY_DRIVER 0xD8 10566aee900SScott Liu 106c18b443cSMichał Mirosław /* FW write command, 0x54 0x?? 0x0, 0x01 */ 107c18b443cSMichał Mirosław #define E_POWER_STATE_SLEEP 0x50 108c18b443cSMichał Mirosław #define E_POWER_STATE_RESUME 0x58 109c18b443cSMichał Mirosław 11066aee900SScott Liu #define MAX_RETRIES 3 11166aee900SScott Liu #define MAX_FW_UPDATE_RETRIES 30 11266aee900SScott Liu 11366aee900SScott Liu #define ELAN_FW_PAGESIZE 132 11466aee900SScott Liu 11566aee900SScott Liu /* calibration timeout definition */ 11622c15e5eSJames Chen #define ELAN_CALI_TIMEOUT_MSEC 12000 11766aee900SScott Liu 118afe10358SDmitry Torokhov #define ELAN_POWERON_DELAY_USEC 500 119afe10358SDmitry Torokhov #define ELAN_RESET_DELAY_MSEC 20 120afe10358SDmitry Torokhov 1214ebfee2bSJohnny Chuang /* FW boot code version */ 1224ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH3900x1_I2C 0x72 1234ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH3900x2_I2C 0x82 1244ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH3900x3_I2C 0x92 1254ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C 0x6D 1264ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C 0x6E 1274ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C 0x77 1284ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C 0x78 1294ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB 0x67 1304ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB 0x68 1314ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB 0x74 1324ebfee2bSJohnny Chuang #define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB 0x75 1334ebfee2bSJohnny Chuang 1349517b95bSMichał Mirosław enum elants_chip_id { 1359517b95bSMichał Mirosław EKTH3500, 1369517b95bSMichał Mirosław EKTF3624, 1379517b95bSMichał Mirosław }; 1389517b95bSMichał Mirosław 13966aee900SScott Liu enum elants_state { 14066aee900SScott Liu ELAN_STATE_NORMAL, 14166aee900SScott Liu ELAN_WAIT_QUEUE_HEADER, 14266aee900SScott Liu ELAN_WAIT_RECALIBRATION, 14366aee900SScott Liu }; 14466aee900SScott Liu 14566aee900SScott Liu enum elants_iap_mode { 14666aee900SScott Liu ELAN_IAP_OPERATIONAL, 14766aee900SScott Liu ELAN_IAP_RECOVERY, 14866aee900SScott Liu }; 14966aee900SScott Liu 15066aee900SScott Liu /* struct elants_data - represents state of Elan touchscreen device */ 15166aee900SScott Liu struct elants_data { 15266aee900SScott Liu struct i2c_client *client; 15366aee900SScott Liu struct input_dev *input; 15466aee900SScott Liu 155afe10358SDmitry Torokhov struct regulator *vcc33; 156afe10358SDmitry Torokhov struct regulator *vccio; 157afe10358SDmitry Torokhov struct gpio_desc *reset_gpio; 158afe10358SDmitry Torokhov 15966aee900SScott Liu u16 fw_version; 16066aee900SScott Liu u8 test_version; 16166aee900SScott Liu u8 solution_version; 16266aee900SScott Liu u8 bc_version; 16366aee900SScott Liu u8 iap_version; 16466aee900SScott Liu u16 hw_version; 1654238e52cSJohnny Chuang u8 major_res; 16666aee900SScott Liu unsigned int x_res; /* resolution in units/mm */ 16766aee900SScott Liu unsigned int y_res; 16866aee900SScott Liu unsigned int x_max; 16966aee900SScott Liu unsigned int y_max; 1709517b95bSMichał Mirosław unsigned int phy_x; 1719517b95bSMichał Mirosław unsigned int phy_y; 17268334dbaSMichał Mirosław struct touchscreen_properties prop; 17366aee900SScott Liu 17466aee900SScott Liu enum elants_state state; 1759517b95bSMichał Mirosław enum elants_chip_id chip_id; 17666aee900SScott Liu enum elants_iap_mode iap_mode; 17766aee900SScott Liu 17866aee900SScott Liu /* Guards against concurrent access to the device via sysfs */ 17966aee900SScott Liu struct mutex sysfs_mutex; 18066aee900SScott Liu 18166aee900SScott Liu u8 cmd_resp[HEADER_SIZE]; 18266aee900SScott Liu struct completion cmd_done; 18366aee900SScott Liu 184afe10358SDmitry Torokhov bool keep_power_in_suspend; 18500f73f97SStephen Boyd 18600f73f97SStephen Boyd /* Must be last to be used for DMA operations */ 18700f73f97SStephen Boyd u8 buf[MAX_PACKET_SIZE] ____cacheline_aligned; 18866aee900SScott Liu }; 18966aee900SScott Liu 19066aee900SScott Liu static int elants_i2c_send(struct i2c_client *client, 19166aee900SScott Liu const void *data, size_t size) 19266aee900SScott Liu { 19366aee900SScott Liu int ret; 19466aee900SScott Liu 19566aee900SScott Liu ret = i2c_master_send(client, data, size); 19666aee900SScott Liu if (ret == size) 19766aee900SScott Liu return 0; 19866aee900SScott Liu 19966aee900SScott Liu if (ret >= 0) 20066aee900SScott Liu ret = -EIO; 20166aee900SScott Liu 20266aee900SScott Liu dev_err(&client->dev, "%s failed (%*ph): %d\n", 20366aee900SScott Liu __func__, (int)size, data, ret); 20466aee900SScott Liu 20566aee900SScott Liu return ret; 20666aee900SScott Liu } 20766aee900SScott Liu 20866aee900SScott Liu static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) 20966aee900SScott Liu { 21066aee900SScott Liu int ret; 21166aee900SScott Liu 21266aee900SScott Liu ret = i2c_master_recv(client, data, size); 21366aee900SScott Liu if (ret == size) 21466aee900SScott Liu return 0; 21566aee900SScott Liu 21666aee900SScott Liu if (ret >= 0) 21766aee900SScott Liu ret = -EIO; 21866aee900SScott Liu 21966aee900SScott Liu dev_err(&client->dev, "%s failed: %d\n", __func__, ret); 22066aee900SScott Liu 22166aee900SScott Liu return ret; 22266aee900SScott Liu } 22366aee900SScott Liu 22466aee900SScott Liu static int elants_i2c_execute_command(struct i2c_client *client, 22566aee900SScott Liu const u8 *cmd, size_t cmd_size, 226918e2844SMichał Mirosław u8 *resp, size_t resp_size, 227918e2844SMichał Mirosław int retries, const char *cmd_name) 22866aee900SScott Liu { 22966aee900SScott Liu struct i2c_msg msgs[2]; 23066aee900SScott Liu int ret; 23166aee900SScott Liu u8 expected_response; 23266aee900SScott Liu 23366aee900SScott Liu switch (cmd[0]) { 23466aee900SScott Liu case CMD_HEADER_READ: 23566aee900SScott Liu expected_response = CMD_HEADER_RESP; 23666aee900SScott Liu break; 23766aee900SScott Liu 23866aee900SScott Liu case CMD_HEADER_6B_READ: 23966aee900SScott Liu expected_response = CMD_HEADER_6B_RESP; 24066aee900SScott Liu break; 24166aee900SScott Liu 242f0b57e19SJohnny.Chuang case CMD_HEADER_ROM_READ: 243f0b57e19SJohnny.Chuang expected_response = CMD_HEADER_ROM_RESP; 244f0b57e19SJohnny.Chuang break; 245f0b57e19SJohnny.Chuang 24666aee900SScott Liu default: 247918e2844SMichał Mirosław dev_err(&client->dev, "(%s): invalid command: %*ph\n", 248918e2844SMichał Mirosław cmd_name, (int)cmd_size, cmd); 24966aee900SScott Liu return -EINVAL; 25066aee900SScott Liu } 25166aee900SScott Liu 252918e2844SMichał Mirosław for (;;) { 25366aee900SScott Liu msgs[0].addr = client->addr; 25466aee900SScott Liu msgs[0].flags = client->flags & I2C_M_TEN; 25566aee900SScott Liu msgs[0].len = cmd_size; 25666aee900SScott Liu msgs[0].buf = (u8 *)cmd; 25766aee900SScott Liu 25866aee900SScott Liu msgs[1].addr = client->addr; 259918e2844SMichał Mirosław msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; 26066aee900SScott Liu msgs[1].flags |= I2C_M_RD; 26166aee900SScott Liu msgs[1].len = resp_size; 26266aee900SScott Liu msgs[1].buf = resp; 26366aee900SScott Liu 26466aee900SScott Liu ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 265918e2844SMichał Mirosław if (ret < 0) { 266918e2844SMichał Mirosław if (--retries > 0) { 267918e2844SMichał Mirosław dev_dbg(&client->dev, 268918e2844SMichał Mirosław "(%s) I2C transfer failed: %pe (retrying)\n", 269918e2844SMichał Mirosław cmd_name, ERR_PTR(ret)); 270918e2844SMichał Mirosław continue; 271918e2844SMichał Mirosław } 27266aee900SScott Liu 273918e2844SMichał Mirosław dev_err(&client->dev, 274918e2844SMichał Mirosław "(%s) I2C transfer failed: %pe\n", 275918e2844SMichał Mirosław cmd_name, ERR_PTR(ret)); 276918e2844SMichał Mirosław return ret; 277918e2844SMichał Mirosław } 278918e2844SMichał Mirosław 279918e2844SMichał Mirosław if (ret != ARRAY_SIZE(msgs) || 280918e2844SMichał Mirosław resp[FW_HDR_TYPE] != expected_response) { 281918e2844SMichał Mirosław if (--retries > 0) { 282918e2844SMichał Mirosław dev_dbg(&client->dev, 283918e2844SMichał Mirosław "(%s) unexpected response: %*ph (retrying)\n", 284918e2844SMichał Mirosław cmd_name, ret, resp); 285918e2844SMichał Mirosław continue; 286918e2844SMichał Mirosław } 287918e2844SMichał Mirosław 288918e2844SMichał Mirosław dev_err(&client->dev, 289918e2844SMichał Mirosław "(%s) unexpected response: %*ph\n", 290918e2844SMichał Mirosław cmd_name, ret, resp); 29166aee900SScott Liu return -EIO; 292918e2844SMichał Mirosław } 29366aee900SScott Liu 29466aee900SScott Liu return 0; 29566aee900SScott Liu } 296918e2844SMichał Mirosław } 29766aee900SScott Liu 29866aee900SScott Liu static int elants_i2c_calibrate(struct elants_data *ts) 29966aee900SScott Liu { 30066aee900SScott Liu struct i2c_client *client = ts->client; 30166aee900SScott Liu int ret, error; 302c18b443cSMichał Mirosław static const u8 w_flashkey[] = { CMD_HEADER_WRITE, 0xC0, 0xE1, 0x5A }; 303c18b443cSMichał Mirosław static const u8 rek[] = { CMD_HEADER_WRITE, 0x29, 0x00, 0x01 }; 30466aee900SScott Liu static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; 30566aee900SScott Liu 30666aee900SScott Liu disable_irq(client->irq); 30766aee900SScott Liu 30866aee900SScott Liu ts->state = ELAN_WAIT_RECALIBRATION; 30966aee900SScott Liu reinit_completion(&ts->cmd_done); 31066aee900SScott Liu 31166aee900SScott Liu elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); 31266aee900SScott Liu elants_i2c_send(client, rek, sizeof(rek)); 31366aee900SScott Liu 31466aee900SScott Liu enable_irq(client->irq); 31566aee900SScott Liu 31666aee900SScott Liu ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, 31766aee900SScott Liu msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); 31866aee900SScott Liu 31966aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 32066aee900SScott Liu 32166aee900SScott Liu if (ret <= 0) { 32266aee900SScott Liu error = ret < 0 ? ret : -ETIMEDOUT; 32366aee900SScott Liu dev_err(&client->dev, 32466aee900SScott Liu "error while waiting for calibration to complete: %d\n", 32566aee900SScott Liu error); 32666aee900SScott Liu return error; 32766aee900SScott Liu } 32866aee900SScott Liu 32966aee900SScott Liu if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { 33066aee900SScott Liu dev_err(&client->dev, 33166aee900SScott Liu "unexpected calibration response: %*ph\n", 33266aee900SScott Liu (int)sizeof(ts->cmd_resp), ts->cmd_resp); 33366aee900SScott Liu return -EINVAL; 33466aee900SScott Liu } 33566aee900SScott Liu 33666aee900SScott Liu return 0; 33766aee900SScott Liu } 33866aee900SScott Liu 33966aee900SScott Liu static int elants_i2c_sw_reset(struct i2c_client *client) 34066aee900SScott Liu { 34166aee900SScott Liu const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; 34266aee900SScott Liu int error; 34366aee900SScott Liu 34466aee900SScott Liu error = elants_i2c_send(client, soft_rst_cmd, 34566aee900SScott Liu sizeof(soft_rst_cmd)); 34666aee900SScott Liu if (error) { 34766aee900SScott Liu dev_err(&client->dev, "software reset failed: %d\n", error); 34866aee900SScott Liu return error; 34966aee900SScott Liu } 35066aee900SScott Liu 35166aee900SScott Liu /* 35266aee900SScott Liu * We should wait at least 10 msec (but no more than 40) before 35366aee900SScott Liu * sending fastboot or IAP command to the device. 35466aee900SScott Liu */ 35566aee900SScott Liu msleep(30); 35666aee900SScott Liu 35766aee900SScott Liu return 0; 35866aee900SScott Liu } 35966aee900SScott Liu 36066aee900SScott Liu static u16 elants_i2c_parse_version(u8 *buf) 36166aee900SScott Liu { 36266aee900SScott Liu return get_unaligned_be32(buf) >> 4; 36366aee900SScott Liu } 36466aee900SScott Liu 365bc1d57feSJohnny Chuang static int elants_i2c_query_hw_version(struct elants_data *ts) 36666aee900SScott Liu { 36766aee900SScott Liu struct i2c_client *client = ts->client; 368918e2844SMichał Mirosław int retry_cnt = MAX_RETRIES; 36966aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; 37066aee900SScott Liu u8 resp[HEADER_SIZE]; 371918e2844SMichał Mirosław int error; 37266aee900SScott Liu 373918e2844SMichał Mirosław while (retry_cnt--) { 37466aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 375918e2844SMichał Mirosław resp, sizeof(resp), 1, 376918e2844SMichał Mirosław "read fw id"); 377918e2844SMichał Mirosław if (error) 378918e2844SMichał Mirosław return error; 379918e2844SMichał Mirosław 38066aee900SScott Liu ts->hw_version = elants_i2c_parse_version(resp); 38166aee900SScott Liu if (ts->hw_version != 0xffff) 38266aee900SScott Liu return 0; 38366aee900SScott Liu } 38466aee900SScott Liu 385bc1d57feSJohnny Chuang dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); 38666aee900SScott Liu 38766aee900SScott Liu return -EINVAL; 38866aee900SScott Liu } 38966aee900SScott Liu 39066aee900SScott Liu static int elants_i2c_query_fw_version(struct elants_data *ts) 39166aee900SScott Liu { 39266aee900SScott Liu struct i2c_client *client = ts->client; 393918e2844SMichał Mirosław int retry_cnt = MAX_RETRIES; 39466aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; 39566aee900SScott Liu u8 resp[HEADER_SIZE]; 396918e2844SMichał Mirosław int error; 39766aee900SScott Liu 398918e2844SMichał Mirosław while (retry_cnt--) { 39966aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 400918e2844SMichał Mirosław resp, sizeof(resp), 1, 401918e2844SMichał Mirosław "read fw version"); 402918e2844SMichał Mirosław if (error) 403918e2844SMichał Mirosław return error; 404918e2844SMichał Mirosław 40566aee900SScott Liu ts->fw_version = elants_i2c_parse_version(resp); 406918e2844SMichał Mirosław if (ts->fw_version != 0x0000 && ts->fw_version != 0xffff) 40766aee900SScott Liu return 0; 408918e2844SMichał Mirosław 409918e2844SMichał Mirosław dev_dbg(&client->dev, "(read fw version) resp %*phC\n", 410918e2844SMichał Mirosław (int)sizeof(resp), resp); 41166aee900SScott Liu } 41266aee900SScott Liu 413918e2844SMichał Mirosław dev_err(&client->dev, "Invalid fw ver: %#04x\n", ts->fw_version); 41466aee900SScott Liu 41566aee900SScott Liu return -EINVAL; 41666aee900SScott Liu } 41766aee900SScott Liu 41866aee900SScott Liu static int elants_i2c_query_test_version(struct elants_data *ts) 41966aee900SScott Liu { 42066aee900SScott Liu struct i2c_client *client = ts->client; 421918e2844SMichał Mirosław int error; 42266aee900SScott Liu u16 version; 42366aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; 42466aee900SScott Liu u8 resp[HEADER_SIZE]; 42566aee900SScott Liu 42666aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 427918e2844SMichał Mirosław resp, sizeof(resp), MAX_RETRIES, 428918e2844SMichał Mirosław "read test version"); 429918e2844SMichał Mirosław if (error) { 430918e2844SMichał Mirosław dev_err(&client->dev, "Failed to read test version\n"); 431918e2844SMichał Mirosław return error; 432918e2844SMichał Mirosław } 433918e2844SMichał Mirosław 43466aee900SScott Liu version = elants_i2c_parse_version(resp); 43566aee900SScott Liu ts->test_version = version >> 8; 43666aee900SScott Liu ts->solution_version = version & 0xff; 43766aee900SScott Liu 43866aee900SScott Liu return 0; 43966aee900SScott Liu } 44066aee900SScott Liu 44166aee900SScott Liu static int elants_i2c_query_bc_version(struct elants_data *ts) 44266aee900SScott Liu { 44366aee900SScott Liu struct i2c_client *client = ts->client; 44466aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; 44566aee900SScott Liu u8 resp[HEADER_SIZE]; 44666aee900SScott Liu u16 version; 44766aee900SScott Liu int error; 44866aee900SScott Liu 44966aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 450918e2844SMichał Mirosław resp, sizeof(resp), 1, 451918e2844SMichał Mirosław "read BC version"); 452918e2844SMichał Mirosław if (error) 45366aee900SScott Liu return error; 45466aee900SScott Liu 45566aee900SScott Liu version = elants_i2c_parse_version(resp); 45666aee900SScott Liu ts->bc_version = version >> 8; 45766aee900SScott Liu ts->iap_version = version & 0xff; 45866aee900SScott Liu 45966aee900SScott Liu return 0; 46066aee900SScott Liu } 46166aee900SScott Liu 4629517b95bSMichał Mirosław static int elants_i2c_query_ts_info_ektf(struct elants_data *ts) 4639517b95bSMichał Mirosław { 4649517b95bSMichał Mirosław struct i2c_client *client = ts->client; 4659517b95bSMichał Mirosław int error; 4669517b95bSMichał Mirosław u8 resp[4]; 4679517b95bSMichał Mirosław u16 phy_x, phy_y; 4689517b95bSMichał Mirosław const u8 get_xres_cmd[] = { 4699517b95bSMichał Mirosław CMD_HEADER_READ, E_ELAN_INFO_X_RES, 0x00, 0x00 4709517b95bSMichał Mirosław }; 4719517b95bSMichał Mirosław const u8 get_yres_cmd[] = { 4729517b95bSMichał Mirosław CMD_HEADER_READ, E_ELAN_INFO_Y_RES, 0x00, 0x00 4739517b95bSMichał Mirosław }; 4749517b95bSMichał Mirosław 4759517b95bSMichał Mirosław /* Get X/Y size in mm */ 4769517b95bSMichał Mirosław error = elants_i2c_execute_command(client, get_xres_cmd, 4779517b95bSMichał Mirosław sizeof(get_xres_cmd), 4789517b95bSMichał Mirosław resp, sizeof(resp), 1, 4799517b95bSMichał Mirosław "get X size"); 4809517b95bSMichał Mirosław if (error) 4819517b95bSMichał Mirosław return error; 4829517b95bSMichał Mirosław 4839517b95bSMichał Mirosław phy_x = resp[2] | ((resp[3] & 0xF0) << 4); 4849517b95bSMichał Mirosław 4859517b95bSMichał Mirosław error = elants_i2c_execute_command(client, get_yres_cmd, 4869517b95bSMichał Mirosław sizeof(get_yres_cmd), 4879517b95bSMichał Mirosław resp, sizeof(resp), 1, 4889517b95bSMichał Mirosław "get Y size"); 4899517b95bSMichał Mirosław if (error) 4909517b95bSMichał Mirosław return error; 4919517b95bSMichał Mirosław 4929517b95bSMichał Mirosław phy_y = resp[2] | ((resp[3] & 0xF0) << 4); 4939517b95bSMichał Mirosław 4949517b95bSMichał Mirosław dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); 4959517b95bSMichał Mirosław 4969517b95bSMichał Mirosław ts->phy_x = phy_x; 4979517b95bSMichał Mirosław ts->phy_y = phy_y; 4989517b95bSMichał Mirosław 4999517b95bSMichał Mirosław /* eKTF doesn't report max size, set it to default values */ 5009517b95bSMichał Mirosław ts->x_max = 2240 - 1; 5019517b95bSMichał Mirosław ts->y_max = 1408 - 1; 5029517b95bSMichał Mirosław 5039517b95bSMichał Mirosław return 0; 5049517b95bSMichał Mirosław } 5059517b95bSMichał Mirosław 5069517b95bSMichał Mirosław static int elants_i2c_query_ts_info_ekth(struct elants_data *ts) 50766aee900SScott Liu { 50866aee900SScott Liu struct i2c_client *client = ts->client; 50966aee900SScott Liu int error; 51066aee900SScott Liu u8 resp[17]; 51166aee900SScott Liu u16 phy_x, phy_y, rows, cols, osr; 51266aee900SScott Liu const u8 get_resolution_cmd[] = { 51366aee900SScott Liu CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 51466aee900SScott Liu }; 51566aee900SScott Liu const u8 get_osr_cmd[] = { 51666aee900SScott Liu CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 51766aee900SScott Liu }; 51866aee900SScott Liu const u8 get_physical_scan_cmd[] = { 51966aee900SScott Liu CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 52066aee900SScott Liu }; 52166aee900SScott Liu const u8 get_physical_drive_cmd[] = { 52266aee900SScott Liu CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 52366aee900SScott Liu }; 52466aee900SScott Liu 52566aee900SScott Liu /* Get trace number */ 52666aee900SScott Liu error = elants_i2c_execute_command(client, 52766aee900SScott Liu get_resolution_cmd, 52866aee900SScott Liu sizeof(get_resolution_cmd), 529918e2844SMichał Mirosław resp, sizeof(resp), 1, 530918e2844SMichał Mirosław "get resolution"); 531918e2844SMichał Mirosław if (error) 53266aee900SScott Liu return error; 53366aee900SScott Liu 53466aee900SScott Liu rows = resp[2] + resp[6] + resp[10]; 53566aee900SScott Liu cols = resp[3] + resp[7] + resp[11]; 53666aee900SScott Liu 5374238e52cSJohnny Chuang /* Get report resolution value of ABS_MT_TOUCH_MAJOR */ 5384238e52cSJohnny Chuang ts->major_res = resp[16]; 5394238e52cSJohnny Chuang 54066aee900SScott Liu /* Process mm_to_pixel information */ 54166aee900SScott Liu error = elants_i2c_execute_command(client, 54266aee900SScott Liu get_osr_cmd, sizeof(get_osr_cmd), 543918e2844SMichał Mirosław resp, sizeof(resp), 1, "get osr"); 544918e2844SMichał Mirosław if (error) 54566aee900SScott Liu return error; 54666aee900SScott Liu 54766aee900SScott Liu osr = resp[3]; 54866aee900SScott Liu 54966aee900SScott Liu error = elants_i2c_execute_command(client, 55066aee900SScott Liu get_physical_scan_cmd, 55166aee900SScott Liu sizeof(get_physical_scan_cmd), 552918e2844SMichał Mirosław resp, sizeof(resp), 1, 553918e2844SMichał Mirosław "get physical scan"); 554918e2844SMichał Mirosław if (error) 55566aee900SScott Liu return error; 55666aee900SScott Liu 55766aee900SScott Liu phy_x = get_unaligned_be16(&resp[2]); 55866aee900SScott Liu 55966aee900SScott Liu error = elants_i2c_execute_command(client, 56066aee900SScott Liu get_physical_drive_cmd, 56166aee900SScott Liu sizeof(get_physical_drive_cmd), 562918e2844SMichał Mirosław resp, sizeof(resp), 1, 563918e2844SMichał Mirosław "get physical drive"); 564918e2844SMichał Mirosław if (error) 56566aee900SScott Liu return error; 56666aee900SScott Liu 56766aee900SScott Liu phy_y = get_unaligned_be16(&resp[2]); 56866aee900SScott Liu 56966aee900SScott Liu dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); 57066aee900SScott Liu 57166aee900SScott Liu if (rows == 0 || cols == 0 || osr == 0) { 57266aee900SScott Liu dev_warn(&client->dev, 57366aee900SScott Liu "invalid trace number data: %d, %d, %d\n", 57466aee900SScott Liu rows, cols, osr); 57566aee900SScott Liu } else { 57666aee900SScott Liu /* translate trace number to TS resolution */ 57766aee900SScott Liu ts->x_max = ELAN_TS_RESOLUTION(rows, osr); 57866aee900SScott Liu ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); 57966aee900SScott Liu ts->y_max = ELAN_TS_RESOLUTION(cols, osr); 58066aee900SScott Liu ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); 5819517b95bSMichał Mirosław ts->phy_x = phy_x; 5829517b95bSMichał Mirosław ts->phy_y = phy_y; 58366aee900SScott Liu } 58466aee900SScott Liu 58566aee900SScott Liu return 0; 58666aee900SScott Liu } 58766aee900SScott Liu 58866aee900SScott Liu static int elants_i2c_fastboot(struct i2c_client *client) 58966aee900SScott Liu { 59066aee900SScott Liu const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; 59166aee900SScott Liu int error; 59266aee900SScott Liu 59366aee900SScott Liu error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); 59466aee900SScott Liu if (error) { 59566aee900SScott Liu dev_err(&client->dev, "boot failed: %d\n", error); 59666aee900SScott Liu return error; 59766aee900SScott Liu } 59866aee900SScott Liu 59966aee900SScott Liu dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); 60066aee900SScott Liu return 0; 60166aee900SScott Liu } 60266aee900SScott Liu 60366aee900SScott Liu static int elants_i2c_initialize(struct elants_data *ts) 60466aee900SScott Liu { 60566aee900SScott Liu struct i2c_client *client = ts->client; 606bc1d57feSJohnny Chuang int error, error2, retry_cnt; 60766aee900SScott Liu const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; 60866aee900SScott Liu const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; 60966aee900SScott Liu u8 buf[HEADER_SIZE]; 61066aee900SScott Liu 61166aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 61266aee900SScott Liu error = elants_i2c_sw_reset(client); 61366aee900SScott Liu if (error) { 61466aee900SScott Liu /* Continue initializing if it's the last try */ 61566aee900SScott Liu if (retry_cnt < MAX_RETRIES - 1) 61666aee900SScott Liu continue; 61766aee900SScott Liu } 61866aee900SScott Liu 61966aee900SScott Liu error = elants_i2c_fastboot(client); 62066aee900SScott Liu if (error) { 62166aee900SScott Liu /* Continue initializing if it's the last try */ 62266aee900SScott Liu if (retry_cnt < MAX_RETRIES - 1) 62366aee900SScott Liu continue; 62466aee900SScott Liu } 62566aee900SScott Liu 62666aee900SScott Liu /* Wait for Hello packet */ 62766aee900SScott Liu msleep(BOOT_TIME_DELAY_MS); 62866aee900SScott Liu 62966aee900SScott Liu error = elants_i2c_read(client, buf, sizeof(buf)); 63066aee900SScott Liu if (error) { 63166aee900SScott Liu dev_err(&client->dev, 63266aee900SScott Liu "failed to read 'hello' packet: %d\n", error); 63366aee900SScott Liu } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { 63466aee900SScott Liu ts->iap_mode = ELAN_IAP_OPERATIONAL; 63566aee900SScott Liu break; 63666aee900SScott Liu } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { 63766aee900SScott Liu /* 63866aee900SScott Liu * Setting error code will mark device 63966aee900SScott Liu * in recovery mode below. 64066aee900SScott Liu */ 64166aee900SScott Liu error = -EIO; 64266aee900SScott Liu break; 64366aee900SScott Liu } else { 64466aee900SScott Liu error = -EINVAL; 64566aee900SScott Liu dev_err(&client->dev, 64666aee900SScott Liu "invalid 'hello' packet: %*ph\n", 64766aee900SScott Liu (int)sizeof(buf), buf); 64866aee900SScott Liu } 64966aee900SScott Liu } 65066aee900SScott Liu 651bc1d57feSJohnny Chuang /* hw version is available even if device in recovery state */ 652bc1d57feSJohnny Chuang error2 = elants_i2c_query_hw_version(ts); 653f0b57e19SJohnny.Chuang if (!error2) 654f0b57e19SJohnny.Chuang error2 = elants_i2c_query_bc_version(ts); 65566aee900SScott Liu if (!error) 656bc1d57feSJohnny Chuang error = error2; 657bc1d57feSJohnny Chuang 65866aee900SScott Liu if (!error) 65966aee900SScott Liu error = elants_i2c_query_fw_version(ts); 660bc1d57feSJohnny Chuang if (!error) 661bc1d57feSJohnny Chuang error = elants_i2c_query_test_version(ts); 6629517b95bSMichał Mirosław 6639517b95bSMichał Mirosław switch (ts->chip_id) { 6649517b95bSMichał Mirosław case EKTH3500: 665bc1d57feSJohnny Chuang if (!error) 6669517b95bSMichał Mirosław error = elants_i2c_query_ts_info_ekth(ts); 6679517b95bSMichał Mirosław break; 6689517b95bSMichał Mirosław case EKTF3624: 6699517b95bSMichał Mirosław if (!error) 6709517b95bSMichał Mirosław error = elants_i2c_query_ts_info_ektf(ts); 6719517b95bSMichał Mirosław break; 6729517b95bSMichał Mirosław default: 673ede6747cSJosh Poimboeuf BUG(); 6749517b95bSMichał Mirosław } 67566aee900SScott Liu 676bc1d57feSJohnny Chuang if (error) 67766aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 67866aee900SScott Liu 67966aee900SScott Liu return 0; 68066aee900SScott Liu } 68166aee900SScott Liu 68266aee900SScott Liu /* 68366aee900SScott Liu * Firmware update interface. 68466aee900SScott Liu */ 68566aee900SScott Liu 68666aee900SScott Liu static int elants_i2c_fw_write_page(struct i2c_client *client, 68766aee900SScott Liu const void *page) 68866aee900SScott Liu { 68966aee900SScott Liu const u8 ack_ok[] = { 0xaa, 0xaa }; 69066aee900SScott Liu u8 buf[2]; 69166aee900SScott Liu int retry; 69266aee900SScott Liu int error; 69366aee900SScott Liu 69466aee900SScott Liu for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { 69566aee900SScott Liu error = elants_i2c_send(client, page, ELAN_FW_PAGESIZE); 69666aee900SScott Liu if (error) { 69766aee900SScott Liu dev_err(&client->dev, 69866aee900SScott Liu "IAP Write Page failed: %d\n", error); 69966aee900SScott Liu continue; 70066aee900SScott Liu } 70166aee900SScott Liu 70266aee900SScott Liu error = elants_i2c_read(client, buf, 2); 70366aee900SScott Liu if (error) { 70466aee900SScott Liu dev_err(&client->dev, 70566aee900SScott Liu "IAP Ack read failed: %d\n", error); 70666aee900SScott Liu return error; 70766aee900SScott Liu } 70866aee900SScott Liu 70966aee900SScott Liu if (!memcmp(buf, ack_ok, sizeof(ack_ok))) 71066aee900SScott Liu return 0; 71166aee900SScott Liu 71266aee900SScott Liu error = -EIO; 71366aee900SScott Liu dev_err(&client->dev, 71466aee900SScott Liu "IAP Get Ack Error [%02x:%02x]\n", 71566aee900SScott Liu buf[0], buf[1]); 71666aee900SScott Liu } 71766aee900SScott Liu 71866aee900SScott Liu return error; 71966aee900SScott Liu } 72066aee900SScott Liu 721f0b57e19SJohnny.Chuang static int elants_i2c_validate_remark_id(struct elants_data *ts, 722f0b57e19SJohnny.Chuang const struct firmware *fw) 723f0b57e19SJohnny.Chuang { 724f0b57e19SJohnny.Chuang struct i2c_client *client = ts->client; 725f0b57e19SJohnny.Chuang int error; 726f0b57e19SJohnny.Chuang const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 }; 727f0b57e19SJohnny.Chuang u8 resp[6] = { 0 }; 728f0b57e19SJohnny.Chuang u16 ts_remark_id = 0; 729f0b57e19SJohnny.Chuang u16 fw_remark_id = 0; 730f0b57e19SJohnny.Chuang 731f0b57e19SJohnny.Chuang /* Compare TS Remark ID and FW Remark ID */ 732f0b57e19SJohnny.Chuang error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 733918e2844SMichał Mirosław resp, sizeof(resp), 734918e2844SMichał Mirosław 1, "read Remark ID"); 735918e2844SMichał Mirosław if (error) 736f0b57e19SJohnny.Chuang return error; 737f0b57e19SJohnny.Chuang 738f0b57e19SJohnny.Chuang ts_remark_id = get_unaligned_be16(&resp[3]); 739f0b57e19SJohnny.Chuang 740f0b57e19SJohnny.Chuang fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]); 741f0b57e19SJohnny.Chuang 742f0b57e19SJohnny.Chuang if (fw_remark_id != ts_remark_id) { 743f0b57e19SJohnny.Chuang dev_err(&client->dev, 744f0b57e19SJohnny.Chuang "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n", 745f0b57e19SJohnny.Chuang ts_remark_id, fw_remark_id); 746f0b57e19SJohnny.Chuang return -EINVAL; 747f0b57e19SJohnny.Chuang } 748f0b57e19SJohnny.Chuang 749f0b57e19SJohnny.Chuang return 0; 750f0b57e19SJohnny.Chuang } 751f0b57e19SJohnny.Chuang 7524ebfee2bSJohnny Chuang static bool elants_i2c_should_check_remark_id(struct elants_data *ts) 7534ebfee2bSJohnny Chuang { 7544ebfee2bSJohnny Chuang struct i2c_client *client = ts->client; 7554ebfee2bSJohnny Chuang const u8 bootcode_version = ts->iap_version; 7564ebfee2bSJohnny Chuang bool check; 7574ebfee2bSJohnny Chuang 7584ebfee2bSJohnny Chuang /* I2C eKTH3900 and eKTH5312 are NOT support Remark ID */ 7594ebfee2bSJohnny Chuang if ((bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x1_I2C) || 7604ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x2_I2C) || 7614ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x3_I2C) || 7624ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C) || 7634ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C) || 7644ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C) || 7654ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C) || 7664ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB) || 7674ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB) || 7684ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB) || 7694ebfee2bSJohnny Chuang (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB)) { 7704ebfee2bSJohnny Chuang dev_dbg(&client->dev, 7714ebfee2bSJohnny Chuang "eKTH3900/eKTH5312(0x%02x) are not support remark id\n", 7724ebfee2bSJohnny Chuang bootcode_version); 7734ebfee2bSJohnny Chuang check = false; 7744ebfee2bSJohnny Chuang } else if (bootcode_version >= 0x60) { 7754ebfee2bSJohnny Chuang check = true; 7764ebfee2bSJohnny Chuang } else { 7774ebfee2bSJohnny Chuang check = false; 7784ebfee2bSJohnny Chuang } 7794ebfee2bSJohnny Chuang 7804ebfee2bSJohnny Chuang return check; 7814ebfee2bSJohnny Chuang } 7824ebfee2bSJohnny Chuang 78366aee900SScott Liu static int elants_i2c_do_update_firmware(struct i2c_client *client, 78466aee900SScott Liu const struct firmware *fw, 78566aee900SScott Liu bool force) 78666aee900SScott Liu { 787f0b57e19SJohnny.Chuang struct elants_data *ts = i2c_get_clientdata(client); 78866aee900SScott Liu const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; 78966aee900SScott Liu const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; 79066aee900SScott Liu const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; 7916fd38502SJames Chen const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 }; 79266aee900SScott Liu u8 buf[HEADER_SIZE]; 79366aee900SScott Liu u16 send_id; 79466aee900SScott Liu int page, n_fw_pages; 79566aee900SScott Liu int error; 7964ebfee2bSJohnny Chuang bool check_remark_id = elants_i2c_should_check_remark_id(ts); 79766aee900SScott Liu 79866aee900SScott Liu /* Recovery mode detection! */ 79966aee900SScott Liu if (force) { 80066aee900SScott Liu dev_dbg(&client->dev, "Recovery mode procedure\n"); 801f0b57e19SJohnny.Chuang 802f0b57e19SJohnny.Chuang if (check_remark_id) { 803f0b57e19SJohnny.Chuang error = elants_i2c_validate_remark_id(ts, fw); 804f0b57e19SJohnny.Chuang if (error) 805f0b57e19SJohnny.Chuang return error; 806f0b57e19SJohnny.Chuang } 807f0b57e19SJohnny.Chuang 80866aee900SScott Liu error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); 809f0b57e19SJohnny.Chuang if (error) { 810f0b57e19SJohnny.Chuang dev_err(&client->dev, "failed to enter IAP mode: %d\n", 811f0b57e19SJohnny.Chuang error); 812f0b57e19SJohnny.Chuang return error; 813f0b57e19SJohnny.Chuang } 81466aee900SScott Liu } else { 81566aee900SScott Liu /* Start IAP Procedure */ 81666aee900SScott Liu dev_dbg(&client->dev, "Normal IAP procedure\n"); 817f0b57e19SJohnny.Chuang 8186fd38502SJames Chen /* Close idle mode */ 8196fd38502SJames Chen error = elants_i2c_send(client, close_idle, sizeof(close_idle)); 8206fd38502SJames Chen if (error) 8216fd38502SJames Chen dev_err(&client->dev, "Failed close idle: %d\n", error); 8226fd38502SJames Chen msleep(60); 823f0b57e19SJohnny.Chuang 82466aee900SScott Liu elants_i2c_sw_reset(client); 8256fd38502SJames Chen msleep(20); 826f0b57e19SJohnny.Chuang 827f0b57e19SJohnny.Chuang if (check_remark_id) { 828f0b57e19SJohnny.Chuang error = elants_i2c_validate_remark_id(ts, fw); 829f0b57e19SJohnny.Chuang if (error) 830f0b57e19SJohnny.Chuang return error; 83166aee900SScott Liu } 83266aee900SScott Liu 833f0b57e19SJohnny.Chuang error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); 83466aee900SScott Liu if (error) { 835f0b57e19SJohnny.Chuang dev_err(&client->dev, "failed to enter IAP mode: %d\n", 836f0b57e19SJohnny.Chuang error); 83766aee900SScott Liu return error; 83866aee900SScott Liu } 839f0b57e19SJohnny.Chuang } 84066aee900SScott Liu 84166aee900SScott Liu msleep(20); 84266aee900SScott Liu 84366aee900SScott Liu /* check IAP state */ 84466aee900SScott Liu error = elants_i2c_read(client, buf, 4); 84566aee900SScott Liu if (error) { 84666aee900SScott Liu dev_err(&client->dev, 84766aee900SScott Liu "failed to read IAP acknowledgement: %d\n", 84866aee900SScott Liu error); 84966aee900SScott Liu return error; 85066aee900SScott Liu } 85166aee900SScott Liu 85266aee900SScott Liu if (memcmp(buf, iap_ack, sizeof(iap_ack))) { 85366aee900SScott Liu dev_err(&client->dev, 85466aee900SScott Liu "failed to enter IAP: %*ph (expected %*ph)\n", 85566aee900SScott Liu (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); 85666aee900SScott Liu return -EIO; 85766aee900SScott Liu } 85866aee900SScott Liu 85966aee900SScott Liu dev_info(&client->dev, "successfully entered IAP mode"); 86066aee900SScott Liu 86166aee900SScott Liu send_id = client->addr; 86266aee900SScott Liu error = elants_i2c_send(client, &send_id, 1); 86366aee900SScott Liu if (error) { 86466aee900SScott Liu dev_err(&client->dev, "sending dummy byte failed: %d\n", 86566aee900SScott Liu error); 86666aee900SScott Liu return error; 86766aee900SScott Liu } 86866aee900SScott Liu 86966aee900SScott Liu /* Clear the last page of Master */ 87066aee900SScott Liu error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); 87166aee900SScott Liu if (error) { 87266aee900SScott Liu dev_err(&client->dev, "clearing of the last page failed: %d\n", 87366aee900SScott Liu error); 87466aee900SScott Liu return error; 87566aee900SScott Liu } 87666aee900SScott Liu 87766aee900SScott Liu error = elants_i2c_read(client, buf, 2); 87866aee900SScott Liu if (error) { 87966aee900SScott Liu dev_err(&client->dev, 88066aee900SScott Liu "failed to read ACK for clearing the last page: %d\n", 88166aee900SScott Liu error); 88266aee900SScott Liu return error; 88366aee900SScott Liu } 88466aee900SScott Liu 88566aee900SScott Liu n_fw_pages = fw->size / ELAN_FW_PAGESIZE; 88666aee900SScott Liu dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); 88766aee900SScott Liu 88866aee900SScott Liu for (page = 0; page < n_fw_pages; page++) { 88966aee900SScott Liu error = elants_i2c_fw_write_page(client, 89066aee900SScott Liu fw->data + page * ELAN_FW_PAGESIZE); 89166aee900SScott Liu if (error) { 89266aee900SScott Liu dev_err(&client->dev, 89366aee900SScott Liu "failed to write FW page %d: %d\n", 89466aee900SScott Liu page, error); 89566aee900SScott Liu return error; 89666aee900SScott Liu } 89766aee900SScott Liu } 89866aee900SScott Liu 89966aee900SScott Liu /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ 90066aee900SScott Liu msleep(300); 90166aee900SScott Liu 90266aee900SScott Liu dev_info(&client->dev, "firmware update completed\n"); 90366aee900SScott Liu return 0; 90466aee900SScott Liu } 90566aee900SScott Liu 90666aee900SScott Liu static int elants_i2c_fw_update(struct elants_data *ts) 90766aee900SScott Liu { 90866aee900SScott Liu struct i2c_client *client = ts->client; 90966aee900SScott Liu const struct firmware *fw; 91037dee1acSCharlie Mooney char *fw_name; 91166aee900SScott Liu int error; 91266aee900SScott Liu 9138c0776a8SDmitry Torokhov fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); 91437dee1acSCharlie Mooney if (!fw_name) 91537dee1acSCharlie Mooney return -ENOMEM; 91637dee1acSCharlie Mooney 91737dee1acSCharlie Mooney dev_info(&client->dev, "requesting fw name = %s\n", fw_name); 91837dee1acSCharlie Mooney error = request_firmware(&fw, fw_name, &client->dev); 91937dee1acSCharlie Mooney kfree(fw_name); 92066aee900SScott Liu if (error) { 92137dee1acSCharlie Mooney dev_err(&client->dev, "failed to request firmware: %d\n", 92237dee1acSCharlie Mooney error); 92366aee900SScott Liu return error; 92466aee900SScott Liu } 92566aee900SScott Liu 92666aee900SScott Liu if (fw->size % ELAN_FW_PAGESIZE) { 92766aee900SScott Liu dev_err(&client->dev, "invalid firmware length: %zu\n", 92866aee900SScott Liu fw->size); 92966aee900SScott Liu error = -EINVAL; 93066aee900SScott Liu goto out; 93166aee900SScott Liu } 93266aee900SScott Liu 93366aee900SScott Liu disable_irq(client->irq); 93466aee900SScott Liu 93566aee900SScott Liu error = elants_i2c_do_update_firmware(client, fw, 93666aee900SScott Liu ts->iap_mode == ELAN_IAP_RECOVERY); 93766aee900SScott Liu if (error) { 93866aee900SScott Liu dev_err(&client->dev, "firmware update failed: %d\n", error); 93966aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 94066aee900SScott Liu goto out_enable_irq; 94166aee900SScott Liu } 94266aee900SScott Liu 94366aee900SScott Liu error = elants_i2c_initialize(ts); 94466aee900SScott Liu if (error) { 94566aee900SScott Liu dev_err(&client->dev, 94666aee900SScott Liu "failed to initialize device after firmware update: %d\n", 94766aee900SScott Liu error); 94866aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 94966aee900SScott Liu goto out_enable_irq; 95066aee900SScott Liu } 95166aee900SScott Liu 95266aee900SScott Liu ts->iap_mode = ELAN_IAP_OPERATIONAL; 95366aee900SScott Liu 95466aee900SScott Liu out_enable_irq: 95566aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 95666aee900SScott Liu enable_irq(client->irq); 95766aee900SScott Liu msleep(100); 95866aee900SScott Liu 95966aee900SScott Liu if (!error) 96066aee900SScott Liu elants_i2c_calibrate(ts); 96166aee900SScott Liu out: 96266aee900SScott Liu release_firmware(fw); 96366aee900SScott Liu return error; 96466aee900SScott Liu } 96566aee900SScott Liu 96666aee900SScott Liu /* 96766aee900SScott Liu * Event reporting. 96866aee900SScott Liu */ 96966aee900SScott Liu 9709517b95bSMichał Mirosław static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf, 9719517b95bSMichał Mirosław size_t packet_size) 97266aee900SScott Liu { 97366aee900SScott Liu struct input_dev *input = ts->input; 97466aee900SScott Liu unsigned int n_fingers; 975f27ad893SJohnny Chuang unsigned int tool_type; 97666aee900SScott Liu u16 finger_state; 97766aee900SScott Liu int i; 97866aee900SScott Liu 97966aee900SScott Liu n_fingers = buf[FW_POS_STATE + 1] & 0x0f; 98066aee900SScott Liu finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | 98166aee900SScott Liu buf[FW_POS_STATE]; 98266aee900SScott Liu 98366aee900SScott Liu dev_dbg(&ts->client->dev, 98466aee900SScott Liu "n_fingers: %u, state: %04x\n", n_fingers, finger_state); 98566aee900SScott Liu 986f27ad893SJohnny Chuang /* Note: all fingers have the same tool type */ 987f27ad893SJohnny Chuang tool_type = buf[FW_POS_TOOL_TYPE] & BIT(0) ? 988f27ad893SJohnny Chuang MT_TOOL_FINGER : MT_TOOL_PALM; 989f27ad893SJohnny Chuang 99066aee900SScott Liu for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { 99166aee900SScott Liu if (finger_state & 1) { 99266aee900SScott Liu unsigned int x, y, p, w; 99366aee900SScott Liu u8 *pos; 99466aee900SScott Liu 99566aee900SScott Liu pos = &buf[FW_POS_XY + i * 3]; 99666aee900SScott Liu x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; 99766aee900SScott Liu y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; 9989517b95bSMichał Mirosław 9999517b95bSMichał Mirosław /* 10009517b95bSMichał Mirosław * eKTF3624 may have use "old" touch-report format, 10019517b95bSMichał Mirosław * depending on a device and TS firmware version. 10029517b95bSMichał Mirosław * For example, ASUS Transformer devices use the "old" 10039517b95bSMichał Mirosław * format, while ASUS Nexus 7 uses the "new" formant. 10049517b95bSMichał Mirosław */ 10059517b95bSMichał Mirosław if (packet_size == PACKET_SIZE_OLD && 10069517b95bSMichał Mirosław ts->chip_id == EKTF3624) { 10079517b95bSMichał Mirosław w = buf[FW_POS_WIDTH + i / 2]; 10089517b95bSMichał Mirosław w >>= 4 * (~i & 1); 10099517b95bSMichał Mirosław w |= w << 4; 10109517b95bSMichał Mirosław w |= !w; 10119517b95bSMichał Mirosław p = w; 10129517b95bSMichał Mirosław } else { 101366aee900SScott Liu p = buf[FW_POS_PRESSURE + i]; 101466aee900SScott Liu w = buf[FW_POS_WIDTH + i]; 10159517b95bSMichał Mirosław } 101666aee900SScott Liu 101766aee900SScott Liu dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", 101866aee900SScott Liu i, x, y, p, w); 101966aee900SScott Liu 102066aee900SScott Liu input_mt_slot(input, i); 1021f27ad893SJohnny Chuang input_mt_report_slot_state(input, tool_type, true); 102268334dbaSMichał Mirosław touchscreen_report_pos(input, &ts->prop, x, y, true); 102366aee900SScott Liu input_event(input, EV_ABS, ABS_MT_PRESSURE, p); 102466aee900SScott Liu input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); 102566aee900SScott Liu 102666aee900SScott Liu n_fingers--; 102766aee900SScott Liu } 102866aee900SScott Liu 102966aee900SScott Liu finger_state >>= 1; 103066aee900SScott Liu } 103166aee900SScott Liu 103266aee900SScott Liu input_mt_sync_frame(input); 103366aee900SScott Liu input_sync(input); 103466aee900SScott Liu } 103566aee900SScott Liu 103666aee900SScott Liu static u8 elants_i2c_calculate_checksum(u8 *buf) 103766aee900SScott Liu { 103866aee900SScott Liu u8 checksum = 0; 103966aee900SScott Liu u8 i; 104066aee900SScott Liu 104166aee900SScott Liu for (i = 0; i < FW_POS_CHECKSUM; i++) 104266aee900SScott Liu checksum += buf[i]; 104366aee900SScott Liu 104466aee900SScott Liu return checksum; 104566aee900SScott Liu } 104666aee900SScott Liu 10479517b95bSMichał Mirosław static void elants_i2c_event(struct elants_data *ts, u8 *buf, 10489517b95bSMichał Mirosław size_t packet_size) 104966aee900SScott Liu { 105066aee900SScott Liu u8 checksum = elants_i2c_calculate_checksum(buf); 105166aee900SScott Liu 105266aee900SScott Liu if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) 105366aee900SScott Liu dev_warn(&ts->client->dev, 105466aee900SScott Liu "%s: invalid checksum for packet %02x: %02x vs. %02x\n", 105566aee900SScott Liu __func__, buf[FW_POS_HEADER], 105666aee900SScott Liu checksum, buf[FW_POS_CHECKSUM]); 105766aee900SScott Liu else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) 105866aee900SScott Liu dev_warn(&ts->client->dev, 105966aee900SScott Liu "%s: unknown packet type: %02x\n", 106066aee900SScott Liu __func__, buf[FW_POS_HEADER]); 106166aee900SScott Liu else 10629517b95bSMichał Mirosław elants_i2c_mt_event(ts, buf, packet_size); 106366aee900SScott Liu } 106466aee900SScott Liu 106566aee900SScott Liu static irqreturn_t elants_i2c_irq(int irq, void *_dev) 106666aee900SScott Liu { 106766aee900SScott Liu const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; 106866aee900SScott Liu struct elants_data *ts = _dev; 106966aee900SScott Liu struct i2c_client *client = ts->client; 107066aee900SScott Liu int report_count, report_len; 107166aee900SScott Liu int i; 107266aee900SScott Liu int len; 107366aee900SScott Liu 107400f73f97SStephen Boyd len = i2c_master_recv_dmasafe(client, ts->buf, sizeof(ts->buf)); 107566aee900SScott Liu if (len < 0) { 107666aee900SScott Liu dev_err(&client->dev, "%s: failed to read data: %d\n", 107766aee900SScott Liu __func__, len); 107866aee900SScott Liu goto out; 107966aee900SScott Liu } 108066aee900SScott Liu 108166aee900SScott Liu dev_dbg(&client->dev, "%s: packet %*ph\n", 108266aee900SScott Liu __func__, HEADER_SIZE, ts->buf); 108366aee900SScott Liu 108466aee900SScott Liu switch (ts->state) { 108566aee900SScott Liu case ELAN_WAIT_RECALIBRATION: 108666aee900SScott Liu if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { 108766aee900SScott Liu memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); 108866aee900SScott Liu complete(&ts->cmd_done); 108966aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 109066aee900SScott Liu } 109166aee900SScott Liu break; 109266aee900SScott Liu 109366aee900SScott Liu case ELAN_WAIT_QUEUE_HEADER: 109466aee900SScott Liu if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) 109566aee900SScott Liu break; 109666aee900SScott Liu 109766aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 10986f49c4f5SGustavo A. R. Silva fallthrough; 109966aee900SScott Liu 110066aee900SScott Liu case ELAN_STATE_NORMAL: 110166aee900SScott Liu 110266aee900SScott Liu switch (ts->buf[FW_HDR_TYPE]) { 110366aee900SScott Liu case CMD_HEADER_HELLO: 110466aee900SScott Liu case CMD_HEADER_RESP: 110566aee900SScott Liu break; 110666aee900SScott Liu 110766aee900SScott Liu case QUEUE_HEADER_WAIT: 110866aee900SScott Liu if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { 110966aee900SScott Liu dev_err(&client->dev, 111066aee900SScott Liu "invalid wait packet %*ph\n", 111166aee900SScott Liu HEADER_SIZE, ts->buf); 111266aee900SScott Liu } else { 111366aee900SScott Liu ts->state = ELAN_WAIT_QUEUE_HEADER; 111466aee900SScott Liu udelay(30); 111566aee900SScott Liu } 111666aee900SScott Liu break; 111766aee900SScott Liu 111866aee900SScott Liu case QUEUE_HEADER_SINGLE: 11199517b95bSMichał Mirosław elants_i2c_event(ts, &ts->buf[HEADER_SIZE], 11209517b95bSMichał Mirosław ts->buf[FW_HDR_LENGTH]); 112166aee900SScott Liu break; 112266aee900SScott Liu 11239517b95bSMichał Mirosław case QUEUE_HEADER_NORMAL2: /* CMD_HEADER_REK */ 11249517b95bSMichał Mirosław /* 11259517b95bSMichał Mirosław * Depending on firmware version, eKTF3624 touchscreens 11269517b95bSMichał Mirosław * may utilize one of these opcodes for the touch events: 11279517b95bSMichał Mirosław * 0x63 (NORMAL) and 0x66 (NORMAL2). The 0x63 is used by 11289517b95bSMichał Mirosław * older firmware version and differs from 0x66 such that 11299517b95bSMichał Mirosław * touch pressure value needs to be adjusted. The 0x66 11309517b95bSMichał Mirosław * opcode of newer firmware is equal to 0x63 of eKTH3500. 11319517b95bSMichał Mirosław */ 11329517b95bSMichał Mirosław if (ts->chip_id != EKTF3624) 11339517b95bSMichał Mirosław break; 11349517b95bSMichał Mirosław 11359517b95bSMichał Mirosław fallthrough; 11369517b95bSMichał Mirosław 113766aee900SScott Liu case QUEUE_HEADER_NORMAL: 113866aee900SScott Liu report_count = ts->buf[FW_HDR_COUNT]; 11391c3415a0SGuenter Roeck if (report_count == 0 || report_count > 3) { 114066aee900SScott Liu dev_err(&client->dev, 11411c3415a0SGuenter Roeck "bad report count: %*ph\n", 114266aee900SScott Liu HEADER_SIZE, ts->buf); 114366aee900SScott Liu break; 114466aee900SScott Liu } 114566aee900SScott Liu 114666aee900SScott Liu report_len = ts->buf[FW_HDR_LENGTH] / report_count; 11479517b95bSMichał Mirosław 11489517b95bSMichał Mirosław if (report_len == PACKET_SIZE_OLD && 11499517b95bSMichał Mirosław ts->chip_id == EKTF3624) { 11509517b95bSMichał Mirosław dev_dbg_once(&client->dev, 11519517b95bSMichał Mirosław "using old report format\n"); 11529517b95bSMichał Mirosław } else if (report_len != PACKET_SIZE) { 115366aee900SScott Liu dev_err(&client->dev, 115466aee900SScott Liu "mismatching report length: %*ph\n", 115566aee900SScott Liu HEADER_SIZE, ts->buf); 115666aee900SScott Liu break; 115766aee900SScott Liu } 115866aee900SScott Liu 115966aee900SScott Liu for (i = 0; i < report_count; i++) { 116066aee900SScott Liu u8 *buf = ts->buf + HEADER_SIZE + 11619517b95bSMichał Mirosław i * report_len; 11629517b95bSMichał Mirosław elants_i2c_event(ts, buf, report_len); 116366aee900SScott Liu } 116466aee900SScott Liu break; 116566aee900SScott Liu 116666aee900SScott Liu default: 116766aee900SScott Liu dev_err(&client->dev, "unknown packet %*ph\n", 116866aee900SScott Liu HEADER_SIZE, ts->buf); 116966aee900SScott Liu break; 117066aee900SScott Liu } 117166aee900SScott Liu break; 117266aee900SScott Liu } 117366aee900SScott Liu 117466aee900SScott Liu out: 117566aee900SScott Liu return IRQ_HANDLED; 117666aee900SScott Liu } 117766aee900SScott Liu 117866aee900SScott Liu /* 117966aee900SScott Liu * sysfs interface 118066aee900SScott Liu */ 118166aee900SScott Liu static ssize_t calibrate_store(struct device *dev, 118266aee900SScott Liu struct device_attribute *attr, 118366aee900SScott Liu const char *buf, size_t count) 118466aee900SScott Liu { 118566aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 118666aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 118766aee900SScott Liu int error; 118866aee900SScott Liu 118966aee900SScott Liu error = mutex_lock_interruptible(&ts->sysfs_mutex); 119066aee900SScott Liu if (error) 119166aee900SScott Liu return error; 119266aee900SScott Liu 119366aee900SScott Liu error = elants_i2c_calibrate(ts); 119466aee900SScott Liu 119566aee900SScott Liu mutex_unlock(&ts->sysfs_mutex); 119666aee900SScott Liu return error ?: count; 119766aee900SScott Liu } 119866aee900SScott Liu 119966aee900SScott Liu static ssize_t write_update_fw(struct device *dev, 120066aee900SScott Liu struct device_attribute *attr, 120166aee900SScott Liu const char *buf, size_t count) 120266aee900SScott Liu { 120366aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 120466aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 120566aee900SScott Liu int error; 120666aee900SScott Liu 120766aee900SScott Liu error = mutex_lock_interruptible(&ts->sysfs_mutex); 120866aee900SScott Liu if (error) 120966aee900SScott Liu return error; 121066aee900SScott Liu 121166aee900SScott Liu error = elants_i2c_fw_update(ts); 121266aee900SScott Liu dev_dbg(dev, "firmware update result: %d\n", error); 121366aee900SScott Liu 121466aee900SScott Liu mutex_unlock(&ts->sysfs_mutex); 121566aee900SScott Liu return error ?: count; 121666aee900SScott Liu } 121766aee900SScott Liu 121866aee900SScott Liu static ssize_t show_iap_mode(struct device *dev, 121966aee900SScott Liu struct device_attribute *attr, char *buf) 122066aee900SScott Liu { 122166aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 122266aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 122366aee900SScott Liu 122466aee900SScott Liu return sprintf(buf, "%s\n", 122566aee900SScott Liu ts->iap_mode == ELAN_IAP_OPERATIONAL ? 122666aee900SScott Liu "Normal" : "Recovery"); 122766aee900SScott Liu } 122866aee900SScott Liu 1229cf520c64SJohnny Chuang static ssize_t show_calibration_count(struct device *dev, 1230cf520c64SJohnny Chuang struct device_attribute *attr, char *buf) 1231cf520c64SJohnny Chuang { 1232cf520c64SJohnny Chuang struct i2c_client *client = to_i2c_client(dev); 1233cf520c64SJohnny Chuang const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_REK, 0x00, 0x01 }; 1234cf520c64SJohnny Chuang u8 resp[HEADER_SIZE]; 1235cf520c64SJohnny Chuang u16 rek_count; 1236cf520c64SJohnny Chuang int error; 1237cf520c64SJohnny Chuang 1238cf520c64SJohnny Chuang error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 1239918e2844SMichał Mirosław resp, sizeof(resp), 1, 1240918e2844SMichał Mirosław "read ReK status"); 1241918e2844SMichał Mirosław if (error) 1242cf520c64SJohnny Chuang return sprintf(buf, "%d\n", error); 1243cf520c64SJohnny Chuang 1244cf520c64SJohnny Chuang rek_count = get_unaligned_be16(&resp[2]); 1245cf520c64SJohnny Chuang return sprintf(buf, "0x%04x\n", rek_count); 1246cf520c64SJohnny Chuang } 1247cf520c64SJohnny Chuang 12486cbaefb4SJoe Perches static DEVICE_ATTR_WO(calibrate); 124966aee900SScott Liu static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL); 1250cf520c64SJohnny Chuang static DEVICE_ATTR(calibration_count, S_IRUGO, show_calibration_count, NULL); 125166aee900SScott Liu static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw); 125266aee900SScott Liu 125366aee900SScott Liu struct elants_version_attribute { 125466aee900SScott Liu struct device_attribute dattr; 125566aee900SScott Liu size_t field_offset; 125666aee900SScott Liu size_t field_size; 125766aee900SScott Liu }; 125866aee900SScott Liu 125966aee900SScott Liu #define __ELANTS_FIELD_SIZE(_field) \ 126066aee900SScott Liu sizeof(((struct elants_data *)NULL)->_field) 126166aee900SScott Liu #define __ELANTS_VERIFY_SIZE(_field) \ 126266aee900SScott Liu (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ 126366aee900SScott Liu __ELANTS_FIELD_SIZE(_field)) 126466aee900SScott Liu #define ELANTS_VERSION_ATTR(_field) \ 126566aee900SScott Liu struct elants_version_attribute elants_ver_attr_##_field = { \ 126666aee900SScott Liu .dattr = __ATTR(_field, S_IRUGO, \ 126766aee900SScott Liu elants_version_attribute_show, NULL), \ 126866aee900SScott Liu .field_offset = offsetof(struct elants_data, _field), \ 126966aee900SScott Liu .field_size = __ELANTS_VERIFY_SIZE(_field), \ 127066aee900SScott Liu } 127166aee900SScott Liu 127266aee900SScott Liu static ssize_t elants_version_attribute_show(struct device *dev, 127366aee900SScott Liu struct device_attribute *dattr, 127466aee900SScott Liu char *buf) 127566aee900SScott Liu { 127666aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 127766aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 127866aee900SScott Liu struct elants_version_attribute *attr = 127966aee900SScott Liu container_of(dattr, struct elants_version_attribute, dattr); 128066aee900SScott Liu u8 *field = (u8 *)((char *)ts + attr->field_offset); 128166aee900SScott Liu unsigned int fmt_size; 128266aee900SScott Liu unsigned int val; 128366aee900SScott Liu 128466aee900SScott Liu if (attr->field_size == 1) { 128566aee900SScott Liu val = *field; 128666aee900SScott Liu fmt_size = 2; /* 2 HEX digits */ 128766aee900SScott Liu } else { 128866aee900SScott Liu val = *(u16 *)field; 128966aee900SScott Liu fmt_size = 4; /* 4 HEX digits */ 129066aee900SScott Liu } 129166aee900SScott Liu 129266aee900SScott Liu return sprintf(buf, "%0*x\n", fmt_size, val); 129366aee900SScott Liu } 129466aee900SScott Liu 129566aee900SScott Liu static ELANTS_VERSION_ATTR(fw_version); 129666aee900SScott Liu static ELANTS_VERSION_ATTR(hw_version); 129766aee900SScott Liu static ELANTS_VERSION_ATTR(test_version); 129866aee900SScott Liu static ELANTS_VERSION_ATTR(solution_version); 129966aee900SScott Liu static ELANTS_VERSION_ATTR(bc_version); 130066aee900SScott Liu static ELANTS_VERSION_ATTR(iap_version); 130166aee900SScott Liu 130266aee900SScott Liu static struct attribute *elants_attributes[] = { 130366aee900SScott Liu &dev_attr_calibrate.attr, 130466aee900SScott Liu &dev_attr_update_fw.attr, 130566aee900SScott Liu &dev_attr_iap_mode.attr, 1306cf520c64SJohnny Chuang &dev_attr_calibration_count.attr, 130766aee900SScott Liu 130866aee900SScott Liu &elants_ver_attr_fw_version.dattr.attr, 130966aee900SScott Liu &elants_ver_attr_hw_version.dattr.attr, 131066aee900SScott Liu &elants_ver_attr_test_version.dattr.attr, 131166aee900SScott Liu &elants_ver_attr_solution_version.dattr.attr, 131266aee900SScott Liu &elants_ver_attr_bc_version.dattr.attr, 131366aee900SScott Liu &elants_ver_attr_iap_version.dattr.attr, 131466aee900SScott Liu NULL 131566aee900SScott Liu }; 131666aee900SScott Liu 131748f960ddSArvind Yadav static const struct attribute_group elants_attribute_group = { 131866aee900SScott Liu .attrs = elants_attributes, 131966aee900SScott Liu }; 132066aee900SScott Liu 1321afe10358SDmitry Torokhov static int elants_i2c_power_on(struct elants_data *ts) 1322afe10358SDmitry Torokhov { 1323afe10358SDmitry Torokhov int error; 1324afe10358SDmitry Torokhov 1325afe10358SDmitry Torokhov /* 1326afe10358SDmitry Torokhov * If we do not have reset gpio assume platform firmware 1327afe10358SDmitry Torokhov * controls regulators and does power them on for us. 1328afe10358SDmitry Torokhov */ 1329afe10358SDmitry Torokhov if (IS_ERR_OR_NULL(ts->reset_gpio)) 1330afe10358SDmitry Torokhov return 0; 1331afe10358SDmitry Torokhov 1332afe10358SDmitry Torokhov error = regulator_enable(ts->vcc33); 1333afe10358SDmitry Torokhov if (error) { 1334afe10358SDmitry Torokhov dev_err(&ts->client->dev, 1335afe10358SDmitry Torokhov "failed to enable vcc33 regulator: %d\n", 1336afe10358SDmitry Torokhov error); 1337a85fbd64SDouglas Anderson return error; 1338afe10358SDmitry Torokhov } 1339afe10358SDmitry Torokhov 1340afe10358SDmitry Torokhov error = regulator_enable(ts->vccio); 1341afe10358SDmitry Torokhov if (error) { 1342afe10358SDmitry Torokhov dev_err(&ts->client->dev, 1343afe10358SDmitry Torokhov "failed to enable vccio regulator: %d\n", 1344afe10358SDmitry Torokhov error); 1345afe10358SDmitry Torokhov regulator_disable(ts->vcc33); 1346a85fbd64SDouglas Anderson return error; 1347afe10358SDmitry Torokhov } 1348afe10358SDmitry Torokhov 1349afe10358SDmitry Torokhov /* 1350afe10358SDmitry Torokhov * We need to wait a bit after powering on controller before 1351afe10358SDmitry Torokhov * we are allowed to release reset GPIO. 1352afe10358SDmitry Torokhov */ 1353afe10358SDmitry Torokhov udelay(ELAN_POWERON_DELAY_USEC); 1354afe10358SDmitry Torokhov 1355afe10358SDmitry Torokhov gpiod_set_value_cansleep(ts->reset_gpio, 0); 1356afe10358SDmitry Torokhov if (error) 1357afe10358SDmitry Torokhov return error; 1358afe10358SDmitry Torokhov 1359afe10358SDmitry Torokhov msleep(ELAN_RESET_DELAY_MSEC); 1360afe10358SDmitry Torokhov 1361afe10358SDmitry Torokhov return 0; 1362afe10358SDmitry Torokhov } 1363afe10358SDmitry Torokhov 1364afe10358SDmitry Torokhov static void elants_i2c_power_off(void *_data) 1365afe10358SDmitry Torokhov { 1366afe10358SDmitry Torokhov struct elants_data *ts = _data; 1367afe10358SDmitry Torokhov 1368afe10358SDmitry Torokhov if (!IS_ERR_OR_NULL(ts->reset_gpio)) { 1369afe10358SDmitry Torokhov /* 1370afe10358SDmitry Torokhov * Activate reset gpio to prevent leakage through the 1371afe10358SDmitry Torokhov * pin once we shut off power to the controller. 1372afe10358SDmitry Torokhov */ 1373afe10358SDmitry Torokhov gpiod_set_value_cansleep(ts->reset_gpio, 1); 1374afe10358SDmitry Torokhov regulator_disable(ts->vccio); 1375afe10358SDmitry Torokhov regulator_disable(ts->vcc33); 1376afe10358SDmitry Torokhov } 1377afe10358SDmitry Torokhov } 1378afe10358SDmitry Torokhov 137965299e8bSHans de Goede #ifdef CONFIG_ACPI 138065299e8bSHans de Goede static const struct acpi_device_id i2c_hid_ids[] = { 138165299e8bSHans de Goede {"ACPI0C50", 0 }, 138265299e8bSHans de Goede {"PNP0C50", 0 }, 138365299e8bSHans de Goede { }, 138465299e8bSHans de Goede }; 138565299e8bSHans de Goede 138665299e8bSHans de Goede static const guid_t i2c_hid_guid = 138765299e8bSHans de Goede GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555, 138865299e8bSHans de Goede 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE); 138965299e8bSHans de Goede 139065299e8bSHans de Goede static bool elants_acpi_is_hid_device(struct device *dev) 139165299e8bSHans de Goede { 139265299e8bSHans de Goede acpi_handle handle = ACPI_HANDLE(dev); 139365299e8bSHans de Goede union acpi_object *obj; 139465299e8bSHans de Goede 139565299e8bSHans de Goede if (acpi_match_device_ids(ACPI_COMPANION(dev), i2c_hid_ids)) 139665299e8bSHans de Goede return false; 139765299e8bSHans de Goede 139865299e8bSHans de Goede obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, ACPI_TYPE_INTEGER); 139965299e8bSHans de Goede if (obj) { 140065299e8bSHans de Goede ACPI_FREE(obj); 140165299e8bSHans de Goede return true; 140265299e8bSHans de Goede } 140365299e8bSHans de Goede 140465299e8bSHans de Goede return false; 140565299e8bSHans de Goede } 140665299e8bSHans de Goede #else 140765299e8bSHans de Goede static bool elants_acpi_is_hid_device(struct device *dev) 140865299e8bSHans de Goede { 140965299e8bSHans de Goede return false; 141065299e8bSHans de Goede } 141165299e8bSHans de Goede #endif 141265299e8bSHans de Goede 141345a4b683STakashi Iwai static int elants_i2c_probe(struct i2c_client *client) 141466aee900SScott Liu { 141566aee900SScott Liu union i2c_smbus_data dummy; 141666aee900SScott Liu struct elants_data *ts; 141766aee900SScott Liu unsigned long irqflags; 141866aee900SScott Liu int error; 141966aee900SScott Liu 142065299e8bSHans de Goede /* Don't bind to i2c-hid compatible devices, these are handled by the i2c-hid drv. */ 142165299e8bSHans de Goede if (elants_acpi_is_hid_device(&client->dev)) { 142265299e8bSHans de Goede dev_warn(&client->dev, "This device appears to be an I2C-HID device, not binding\n"); 142365299e8bSHans de Goede return -ENODEV; 142465299e8bSHans de Goede } 142565299e8bSHans de Goede 142666aee900SScott Liu if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 142765299e8bSHans de Goede dev_err(&client->dev, "I2C check functionality error\n"); 142866aee900SScott Liu return -ENXIO; 142966aee900SScott Liu } 143066aee900SScott Liu 143166aee900SScott Liu ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); 143266aee900SScott Liu if (!ts) 143366aee900SScott Liu return -ENOMEM; 143466aee900SScott Liu 143566aee900SScott Liu mutex_init(&ts->sysfs_mutex); 143666aee900SScott Liu init_completion(&ts->cmd_done); 143766aee900SScott Liu 143866aee900SScott Liu ts->client = client; 1439b9c0ebb8STakashi Iwai ts->chip_id = (enum elants_chip_id)(uintptr_t)device_get_match_data(&client->dev); 144066aee900SScott Liu i2c_set_clientdata(client, ts); 144166aee900SScott Liu 1442afe10358SDmitry Torokhov ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); 1443afe10358SDmitry Torokhov if (IS_ERR(ts->vcc33)) { 1444afe10358SDmitry Torokhov error = PTR_ERR(ts->vcc33); 1445afe10358SDmitry Torokhov if (error != -EPROBE_DEFER) 1446afe10358SDmitry Torokhov dev_err(&client->dev, 1447afe10358SDmitry Torokhov "Failed to get 'vcc33' regulator: %d\n", 1448afe10358SDmitry Torokhov error); 1449afe10358SDmitry Torokhov return error; 1450afe10358SDmitry Torokhov } 1451afe10358SDmitry Torokhov 1452afe10358SDmitry Torokhov ts->vccio = devm_regulator_get(&client->dev, "vccio"); 1453afe10358SDmitry Torokhov if (IS_ERR(ts->vccio)) { 1454afe10358SDmitry Torokhov error = PTR_ERR(ts->vccio); 1455afe10358SDmitry Torokhov if (error != -EPROBE_DEFER) 1456afe10358SDmitry Torokhov dev_err(&client->dev, 1457afe10358SDmitry Torokhov "Failed to get 'vccio' regulator: %d\n", 1458afe10358SDmitry Torokhov error); 1459afe10358SDmitry Torokhov return error; 1460afe10358SDmitry Torokhov } 1461afe10358SDmitry Torokhov 1462a85fbd64SDouglas Anderson ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); 1463afe10358SDmitry Torokhov if (IS_ERR(ts->reset_gpio)) { 1464afe10358SDmitry Torokhov error = PTR_ERR(ts->reset_gpio); 1465afe10358SDmitry Torokhov 1466afe10358SDmitry Torokhov if (error == -EPROBE_DEFER) 1467afe10358SDmitry Torokhov return error; 1468afe10358SDmitry Torokhov 1469afe10358SDmitry Torokhov if (error != -ENOENT && error != -ENOSYS) { 1470afe10358SDmitry Torokhov dev_err(&client->dev, 1471afe10358SDmitry Torokhov "failed to get reset gpio: %d\n", 1472afe10358SDmitry Torokhov error); 1473afe10358SDmitry Torokhov return error; 1474afe10358SDmitry Torokhov } 1475afe10358SDmitry Torokhov 1476afe10358SDmitry Torokhov ts->keep_power_in_suspend = true; 1477afe10358SDmitry Torokhov } 1478afe10358SDmitry Torokhov 1479afe10358SDmitry Torokhov error = elants_i2c_power_on(ts); 1480afe10358SDmitry Torokhov if (error) 1481afe10358SDmitry Torokhov return error; 1482afe10358SDmitry Torokhov 1483b083704fSCai Huoqing error = devm_add_action_or_reset(&client->dev, 1484b083704fSCai Huoqing elants_i2c_power_off, ts); 1485afe10358SDmitry Torokhov if (error) { 1486afe10358SDmitry Torokhov dev_err(&client->dev, 1487afe10358SDmitry Torokhov "failed to install power off action: %d\n", error); 1488afe10358SDmitry Torokhov return error; 1489afe10358SDmitry Torokhov } 1490afe10358SDmitry Torokhov 1491afe10358SDmitry Torokhov /* Make sure there is something at this address */ 1492afe10358SDmitry Torokhov if (i2c_smbus_xfer(client->adapter, client->addr, 0, 1493afe10358SDmitry Torokhov I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { 1494afe10358SDmitry Torokhov dev_err(&client->dev, "nothing at this address\n"); 1495afe10358SDmitry Torokhov return -ENXIO; 1496afe10358SDmitry Torokhov } 1497afe10358SDmitry Torokhov 149866aee900SScott Liu error = elants_i2c_initialize(ts); 149966aee900SScott Liu if (error) { 150066aee900SScott Liu dev_err(&client->dev, "failed to initialize: %d\n", error); 150166aee900SScott Liu return error; 150266aee900SScott Liu } 150366aee900SScott Liu 150466aee900SScott Liu ts->input = devm_input_allocate_device(&client->dev); 150566aee900SScott Liu if (!ts->input) { 150666aee900SScott Liu dev_err(&client->dev, "Failed to allocate input device\n"); 150766aee900SScott Liu return -ENOMEM; 150866aee900SScott Liu } 150966aee900SScott Liu 151066aee900SScott Liu ts->input->name = "Elan Touchscreen"; 151166aee900SScott Liu ts->input->id.bustype = BUS_I2C; 151266aee900SScott Liu 151366aee900SScott Liu /* Multitouch input params setup */ 151466aee900SScott Liu 151566aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); 151666aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); 151766aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 151866aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); 1519f27ad893SJohnny Chuang input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE, 1520f27ad893SJohnny Chuang 0, MT_TOOL_PALM, 0, 0); 15219517b95bSMichał Mirosław 15229517b95bSMichał Mirosław touchscreen_parse_properties(ts->input, true, &ts->prop); 15239517b95bSMichał Mirosław 1524781bab32SDmitry Osipenko if (ts->chip_id == EKTF3624 && ts->phy_x && ts->phy_y) { 15259517b95bSMichał Mirosław /* calculate resolution from size */ 15269517b95bSMichał Mirosław ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x); 15279517b95bSMichał Mirosław ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y); 15289517b95bSMichał Mirosław } 15299517b95bSMichał Mirosław 153066aee900SScott Liu input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); 153166aee900SScott Liu input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); 15324238e52cSJohnny Chuang input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); 153366aee900SScott Liu 15346def17b1SMichał Mirosław error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, 15356def17b1SMichał Mirosław INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 15366def17b1SMichał Mirosław if (error) { 15376def17b1SMichał Mirosław dev_err(&client->dev, 15386def17b1SMichał Mirosław "failed to initialize MT slots: %d\n", error); 15396def17b1SMichał Mirosław return error; 15406def17b1SMichał Mirosław } 15416def17b1SMichał Mirosław 154266aee900SScott Liu error = input_register_device(ts->input); 154366aee900SScott Liu if (error) { 154466aee900SScott Liu dev_err(&client->dev, 154566aee900SScott Liu "unable to register input device: %d\n", error); 154666aee900SScott Liu return error; 154766aee900SScott Liu } 154866aee900SScott Liu 154966aee900SScott Liu /* 15504c83c071SDmitry Torokhov * Platform code (ACPI, DTS) should normally set up interrupt 15514c83c071SDmitry Torokhov * for us, but in case it did not let's fall back to using falling 15524c83c071SDmitry Torokhov * edge to be compatible with older Chromebooks. 155366aee900SScott Liu */ 15544c83c071SDmitry Torokhov irqflags = irq_get_trigger_type(client->irq); 15554c83c071SDmitry Torokhov if (!irqflags) 15564c83c071SDmitry Torokhov irqflags = IRQF_TRIGGER_FALLING; 155766aee900SScott Liu 155866aee900SScott Liu error = devm_request_threaded_irq(&client->dev, client->irq, 155966aee900SScott Liu NULL, elants_i2c_irq, 156066aee900SScott Liu irqflags | IRQF_ONESHOT, 156166aee900SScott Liu client->name, ts); 156266aee900SScott Liu if (error) { 156366aee900SScott Liu dev_err(&client->dev, "Failed to register interrupt\n"); 156466aee900SScott Liu return error; 156566aee900SScott Liu } 156666aee900SScott Liu 156766aee900SScott Liu /* 156866aee900SScott Liu * Systems using device tree should set up wakeup via DTS, 156966aee900SScott Liu * the rest will configure device as wakeup source by default. 157066aee900SScott Liu */ 157166aee900SScott Liu if (!client->dev.of_node) 157266aee900SScott Liu device_init_wakeup(&client->dev, true); 157366aee900SScott Liu 1574*2e758f53SRaul E Rangel /* 1575*2e758f53SRaul E Rangel * The wake IRQ should be declared via device tree instead of assuming 1576*2e758f53SRaul E Rangel * the IRQ can wake the system. This is here for legacy reasons and 1577*2e758f53SRaul E Rangel * will be removed once the i2c-core supports querying ACPI for wake 1578*2e758f53SRaul E Rangel * capabilities. 1579*2e758f53SRaul E Rangel */ 1580*2e758f53SRaul E Rangel if (!client->dev.power.wakeirq) 1581*2e758f53SRaul E Rangel dev_pm_set_wake_irq(&client->dev, client->irq); 1582*2e758f53SRaul E Rangel 15838db69a9aSAndi Shyti error = devm_device_add_group(&client->dev, &elants_attribute_group); 158466aee900SScott Liu if (error) { 158566aee900SScott Liu dev_err(&client->dev, "failed to create sysfs attributes: %d\n", 158666aee900SScott Liu error); 158766aee900SScott Liu return error; 158866aee900SScott Liu } 158966aee900SScott Liu 159066aee900SScott Liu return 0; 159166aee900SScott Liu } 159266aee900SScott Liu 159366aee900SScott Liu static int __maybe_unused elants_i2c_suspend(struct device *dev) 159466aee900SScott Liu { 159566aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 159666aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 1597c18b443cSMichał Mirosław const u8 set_sleep_cmd[] = { 1598c18b443cSMichał Mirosław CMD_HEADER_WRITE, E_POWER_STATE_SLEEP, 0x00, 0x01 1599c18b443cSMichał Mirosław }; 160066aee900SScott Liu int retry_cnt; 160166aee900SScott Liu int error; 160266aee900SScott Liu 160366aee900SScott Liu /* Command not support in IAP recovery mode */ 160466aee900SScott Liu if (ts->iap_mode != ELAN_IAP_OPERATIONAL) 160566aee900SScott Liu return -EBUSY; 160666aee900SScott Liu 160766aee900SScott Liu disable_irq(client->irq); 160866aee900SScott Liu 1609478e5ed1SJames Chen if (device_may_wakeup(dev)) { 1610478e5ed1SJames Chen /* 1611478e5ed1SJames Chen * The device will automatically enter idle mode 1612478e5ed1SJames Chen * that has reduced power consumption. 1613478e5ed1SJames Chen */ 1614*2e758f53SRaul E Rangel return 0; 1615478e5ed1SJames Chen } else if (ts->keep_power_in_suspend) { 161666aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 161766aee900SScott Liu error = elants_i2c_send(client, set_sleep_cmd, 161866aee900SScott Liu sizeof(set_sleep_cmd)); 161966aee900SScott Liu if (!error) 162066aee900SScott Liu break; 162166aee900SScott Liu 1622afe10358SDmitry Torokhov dev_err(&client->dev, 1623afe10358SDmitry Torokhov "suspend command failed: %d\n", error); 162466aee900SScott Liu } 1625afe10358SDmitry Torokhov } else { 1626afe10358SDmitry Torokhov elants_i2c_power_off(ts); 1627afe10358SDmitry Torokhov } 162866aee900SScott Liu 162966aee900SScott Liu return 0; 163066aee900SScott Liu } 163166aee900SScott Liu 163266aee900SScott Liu static int __maybe_unused elants_i2c_resume(struct device *dev) 163366aee900SScott Liu { 163466aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 163566aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 1636c18b443cSMichał Mirosław const u8 set_active_cmd[] = { 1637c18b443cSMichał Mirosław CMD_HEADER_WRITE, E_POWER_STATE_RESUME, 0x00, 0x01 1638c18b443cSMichał Mirosław }; 163966aee900SScott Liu int retry_cnt; 164066aee900SScott Liu int error; 164166aee900SScott Liu 1642478e5ed1SJames Chen if (device_may_wakeup(dev)) { 1643478e5ed1SJames Chen elants_i2c_sw_reset(client); 1644478e5ed1SJames Chen } else if (ts->keep_power_in_suspend) { 164566aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 164666aee900SScott Liu error = elants_i2c_send(client, set_active_cmd, 164766aee900SScott Liu sizeof(set_active_cmd)); 164866aee900SScott Liu if (!error) 164966aee900SScott Liu break; 165066aee900SScott Liu 1651afe10358SDmitry Torokhov dev_err(&client->dev, 1652afe10358SDmitry Torokhov "resume command failed: %d\n", error); 1653afe10358SDmitry Torokhov } 1654afe10358SDmitry Torokhov } else { 1655afe10358SDmitry Torokhov elants_i2c_power_on(ts); 1656afe10358SDmitry Torokhov elants_i2c_initialize(ts); 165766aee900SScott Liu } 165866aee900SScott Liu 165966aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 166066aee900SScott Liu enable_irq(client->irq); 166166aee900SScott Liu 166266aee900SScott Liu return 0; 166366aee900SScott Liu } 166466aee900SScott Liu 166566aee900SScott Liu static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, 166666aee900SScott Liu elants_i2c_suspend, elants_i2c_resume); 166766aee900SScott Liu 166866aee900SScott Liu static const struct i2c_device_id elants_i2c_id[] = { 16699517b95bSMichał Mirosław { DEVICE_NAME, EKTH3500 }, 16709517b95bSMichał Mirosław { "ekth3500", EKTH3500 }, 16719517b95bSMichał Mirosław { "ektf3624", EKTF3624 }, 167266aee900SScott Liu { } 167366aee900SScott Liu }; 167466aee900SScott Liu MODULE_DEVICE_TABLE(i2c, elants_i2c_id); 167566aee900SScott Liu 167666aee900SScott Liu #ifdef CONFIG_ACPI 167766aee900SScott Liu static const struct acpi_device_id elants_acpi_id[] = { 16789517b95bSMichał Mirosław { "ELAN0001", EKTH3500 }, 167966aee900SScott Liu { } 168066aee900SScott Liu }; 168166aee900SScott Liu MODULE_DEVICE_TABLE(acpi, elants_acpi_id); 168266aee900SScott Liu #endif 168366aee900SScott Liu 168466aee900SScott Liu #ifdef CONFIG_OF 168566aee900SScott Liu static const struct of_device_id elants_of_match[] = { 1686b9c0ebb8STakashi Iwai { .compatible = "elan,ekth3500", .data = (void *)EKTH3500 }, 1687b9c0ebb8STakashi Iwai { .compatible = "elan,ektf3624", .data = (void *)EKTF3624 }, 168866aee900SScott Liu { /* sentinel */ } 168966aee900SScott Liu }; 169066aee900SScott Liu MODULE_DEVICE_TABLE(of, elants_of_match); 169166aee900SScott Liu #endif 169266aee900SScott Liu 169366aee900SScott Liu static struct i2c_driver elants_i2c_driver = { 169445a4b683STakashi Iwai .probe_new = elants_i2c_probe, 169566aee900SScott Liu .id_table = elants_i2c_id, 169666aee900SScott Liu .driver = { 169766aee900SScott Liu .name = DEVICE_NAME, 169866aee900SScott Liu .pm = &elants_i2c_pm_ops, 169966aee900SScott Liu .acpi_match_table = ACPI_PTR(elants_acpi_id), 170066aee900SScott Liu .of_match_table = of_match_ptr(elants_of_match), 17019f6a07b6SDmitry Torokhov .probe_type = PROBE_PREFER_ASYNCHRONOUS, 170266aee900SScott Liu }, 170366aee900SScott Liu }; 170466aee900SScott Liu module_i2c_driver(elants_i2c_driver); 170566aee900SScott Liu 170666aee900SScott Liu MODULE_AUTHOR("Scott Liu <scott.liu@emc.com.tw>"); 170766aee900SScott Liu MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); 170866aee900SScott Liu MODULE_LICENSE("GPL"); 1709