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> 39afe10358SDmitry Torokhov #include <linux/gpio/consumer.h> 40afe10358SDmitry Torokhov #include <linux/regulator/consumer.h> 4166aee900SScott Liu #include <asm/unaligned.h> 4266aee900SScott Liu 4366aee900SScott Liu /* Device, Driver information */ 4466aee900SScott Liu #define DEVICE_NAME "elants_i2c" 4566aee900SScott Liu 4666aee900SScott Liu /* Convert from rows or columns into resolution */ 4766aee900SScott Liu #define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) 4866aee900SScott Liu 4966aee900SScott Liu /* FW header data */ 5066aee900SScott Liu #define HEADER_SIZE 4 5166aee900SScott Liu #define FW_HDR_TYPE 0 5266aee900SScott Liu #define FW_HDR_COUNT 1 5366aee900SScott Liu #define FW_HDR_LENGTH 2 5466aee900SScott Liu 5566aee900SScott Liu /* Buffer mode Queue Header information */ 5666aee900SScott Liu #define QUEUE_HEADER_SINGLE 0x62 5766aee900SScott Liu #define QUEUE_HEADER_NORMAL 0X63 5866aee900SScott Liu #define QUEUE_HEADER_WAIT 0x64 5966aee900SScott Liu 6066aee900SScott Liu /* Command header definition */ 6166aee900SScott Liu #define CMD_HEADER_WRITE 0x54 6266aee900SScott Liu #define CMD_HEADER_READ 0x53 6366aee900SScott Liu #define CMD_HEADER_6B_READ 0x5B 64f0b57e19SJohnny.Chuang #define CMD_HEADER_ROM_READ 0x96 6566aee900SScott Liu #define CMD_HEADER_RESP 0x52 6666aee900SScott Liu #define CMD_HEADER_6B_RESP 0x9B 67f0b57e19SJohnny.Chuang #define CMD_HEADER_ROM_RESP 0x95 6866aee900SScott Liu #define CMD_HEADER_HELLO 0x55 6966aee900SScott Liu #define CMD_HEADER_REK 0x66 7066aee900SScott Liu 7166aee900SScott Liu /* FW position data */ 7266aee900SScott Liu #define PACKET_SIZE 55 7366aee900SScott Liu #define MAX_CONTACT_NUM 10 7466aee900SScott Liu #define FW_POS_HEADER 0 7566aee900SScott Liu #define FW_POS_STATE 1 7666aee900SScott Liu #define FW_POS_TOTAL 2 7766aee900SScott Liu #define FW_POS_XY 3 78f27ad893SJohnny Chuang #define FW_POS_TOOL_TYPE 33 7966aee900SScott Liu #define FW_POS_CHECKSUM 34 8066aee900SScott Liu #define FW_POS_WIDTH 35 8166aee900SScott Liu #define FW_POS_PRESSURE 45 8266aee900SScott Liu 8366aee900SScott Liu #define HEADER_REPORT_10_FINGER 0x62 8466aee900SScott Liu 8566aee900SScott Liu /* Header (4 bytes) plus 3 fill 10-finger packets */ 8666aee900SScott Liu #define MAX_PACKET_SIZE 169 8766aee900SScott Liu 8866aee900SScott Liu #define BOOT_TIME_DELAY_MS 50 8966aee900SScott Liu 9066aee900SScott Liu /* FW read command, 0x53 0x?? 0x0, 0x01 */ 9166aee900SScott Liu #define E_ELAN_INFO_FW_VER 0x00 9266aee900SScott Liu #define E_ELAN_INFO_BC_VER 0x10 93*93f63406SJohnny Chuang #define E_ELAN_INFO_REK 0xD0 9466aee900SScott Liu #define E_ELAN_INFO_TEST_VER 0xE0 9566aee900SScott Liu #define E_ELAN_INFO_FW_ID 0xF0 9666aee900SScott Liu #define E_INFO_OSR 0xD6 9766aee900SScott Liu #define E_INFO_PHY_SCAN 0xD7 9866aee900SScott Liu #define E_INFO_PHY_DRIVER 0xD8 9966aee900SScott Liu 10066aee900SScott Liu #define MAX_RETRIES 3 10166aee900SScott Liu #define MAX_FW_UPDATE_RETRIES 30 10266aee900SScott Liu 10366aee900SScott Liu #define ELAN_FW_PAGESIZE 132 10466aee900SScott Liu 10566aee900SScott Liu /* calibration timeout definition */ 10622c15e5eSJames Chen #define ELAN_CALI_TIMEOUT_MSEC 12000 10766aee900SScott Liu 108afe10358SDmitry Torokhov #define ELAN_POWERON_DELAY_USEC 500 109afe10358SDmitry Torokhov #define ELAN_RESET_DELAY_MSEC 20 110afe10358SDmitry Torokhov 11166aee900SScott Liu enum elants_state { 11266aee900SScott Liu ELAN_STATE_NORMAL, 11366aee900SScott Liu ELAN_WAIT_QUEUE_HEADER, 11466aee900SScott Liu ELAN_WAIT_RECALIBRATION, 11566aee900SScott Liu }; 11666aee900SScott Liu 11766aee900SScott Liu enum elants_iap_mode { 11866aee900SScott Liu ELAN_IAP_OPERATIONAL, 11966aee900SScott Liu ELAN_IAP_RECOVERY, 12066aee900SScott Liu }; 12166aee900SScott Liu 12266aee900SScott Liu /* struct elants_data - represents state of Elan touchscreen device */ 12366aee900SScott Liu struct elants_data { 12466aee900SScott Liu struct i2c_client *client; 12566aee900SScott Liu struct input_dev *input; 12666aee900SScott Liu 127afe10358SDmitry Torokhov struct regulator *vcc33; 128afe10358SDmitry Torokhov struct regulator *vccio; 129afe10358SDmitry Torokhov struct gpio_desc *reset_gpio; 130afe10358SDmitry Torokhov 13166aee900SScott Liu u16 fw_version; 13266aee900SScott Liu u8 test_version; 13366aee900SScott Liu u8 solution_version; 13466aee900SScott Liu u8 bc_version; 13566aee900SScott Liu u8 iap_version; 13666aee900SScott Liu u16 hw_version; 1374238e52cSJohnny Chuang u8 major_res; 13866aee900SScott Liu unsigned int x_res; /* resolution in units/mm */ 13966aee900SScott Liu unsigned int y_res; 14066aee900SScott Liu unsigned int x_max; 14166aee900SScott Liu unsigned int y_max; 14268334dbaSMichał Mirosław struct touchscreen_properties prop; 14366aee900SScott Liu 14466aee900SScott Liu enum elants_state state; 14566aee900SScott Liu enum elants_iap_mode iap_mode; 14666aee900SScott Liu 14766aee900SScott Liu /* Guards against concurrent access to the device via sysfs */ 14866aee900SScott Liu struct mutex sysfs_mutex; 14966aee900SScott Liu 15066aee900SScott Liu u8 cmd_resp[HEADER_SIZE]; 15166aee900SScott Liu struct completion cmd_done; 15266aee900SScott Liu 15366aee900SScott Liu bool wake_irq_enabled; 154afe10358SDmitry Torokhov bool keep_power_in_suspend; 15500f73f97SStephen Boyd 15600f73f97SStephen Boyd /* Must be last to be used for DMA operations */ 15700f73f97SStephen Boyd u8 buf[MAX_PACKET_SIZE] ____cacheline_aligned; 15866aee900SScott Liu }; 15966aee900SScott Liu 16066aee900SScott Liu static int elants_i2c_send(struct i2c_client *client, 16166aee900SScott Liu const void *data, size_t size) 16266aee900SScott Liu { 16366aee900SScott Liu int ret; 16466aee900SScott Liu 16566aee900SScott Liu ret = i2c_master_send(client, data, size); 16666aee900SScott Liu if (ret == size) 16766aee900SScott Liu return 0; 16866aee900SScott Liu 16966aee900SScott Liu if (ret >= 0) 17066aee900SScott Liu ret = -EIO; 17166aee900SScott Liu 17266aee900SScott Liu dev_err(&client->dev, "%s failed (%*ph): %d\n", 17366aee900SScott Liu __func__, (int)size, data, ret); 17466aee900SScott Liu 17566aee900SScott Liu return ret; 17666aee900SScott Liu } 17766aee900SScott Liu 17866aee900SScott Liu static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) 17966aee900SScott Liu { 18066aee900SScott Liu int ret; 18166aee900SScott Liu 18266aee900SScott Liu ret = i2c_master_recv(client, data, size); 18366aee900SScott Liu if (ret == size) 18466aee900SScott Liu return 0; 18566aee900SScott Liu 18666aee900SScott Liu if (ret >= 0) 18766aee900SScott Liu ret = -EIO; 18866aee900SScott Liu 18966aee900SScott Liu dev_err(&client->dev, "%s failed: %d\n", __func__, ret); 19066aee900SScott Liu 19166aee900SScott Liu return ret; 19266aee900SScott Liu } 19366aee900SScott Liu 19466aee900SScott Liu static int elants_i2c_execute_command(struct i2c_client *client, 19566aee900SScott Liu const u8 *cmd, size_t cmd_size, 196918e2844SMichał Mirosław u8 *resp, size_t resp_size, 197918e2844SMichał Mirosław int retries, const char *cmd_name) 19866aee900SScott Liu { 19966aee900SScott Liu struct i2c_msg msgs[2]; 20066aee900SScott Liu int ret; 20166aee900SScott Liu u8 expected_response; 20266aee900SScott Liu 20366aee900SScott Liu switch (cmd[0]) { 20466aee900SScott Liu case CMD_HEADER_READ: 20566aee900SScott Liu expected_response = CMD_HEADER_RESP; 20666aee900SScott Liu break; 20766aee900SScott Liu 20866aee900SScott Liu case CMD_HEADER_6B_READ: 20966aee900SScott Liu expected_response = CMD_HEADER_6B_RESP; 21066aee900SScott Liu break; 21166aee900SScott Liu 212f0b57e19SJohnny.Chuang case CMD_HEADER_ROM_READ: 213f0b57e19SJohnny.Chuang expected_response = CMD_HEADER_ROM_RESP; 214f0b57e19SJohnny.Chuang break; 215f0b57e19SJohnny.Chuang 21666aee900SScott Liu default: 217918e2844SMichał Mirosław dev_err(&client->dev, "(%s): invalid command: %*ph\n", 218918e2844SMichał Mirosław cmd_name, (int)cmd_size, cmd); 21966aee900SScott Liu return -EINVAL; 22066aee900SScott Liu } 22166aee900SScott Liu 222918e2844SMichał Mirosław for (;;) { 22366aee900SScott Liu msgs[0].addr = client->addr; 22466aee900SScott Liu msgs[0].flags = client->flags & I2C_M_TEN; 22566aee900SScott Liu msgs[0].len = cmd_size; 22666aee900SScott Liu msgs[0].buf = (u8 *)cmd; 22766aee900SScott Liu 22866aee900SScott Liu msgs[1].addr = client->addr; 229918e2844SMichał Mirosław msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; 23066aee900SScott Liu msgs[1].flags |= I2C_M_RD; 23166aee900SScott Liu msgs[1].len = resp_size; 23266aee900SScott Liu msgs[1].buf = resp; 23366aee900SScott Liu 23466aee900SScott Liu ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 235918e2844SMichał Mirosław if (ret < 0) { 236918e2844SMichał Mirosław if (--retries > 0) { 237918e2844SMichał Mirosław dev_dbg(&client->dev, 238918e2844SMichał Mirosław "(%s) I2C transfer failed: %pe (retrying)\n", 239918e2844SMichał Mirosław cmd_name, ERR_PTR(ret)); 240918e2844SMichał Mirosław continue; 241918e2844SMichał Mirosław } 24266aee900SScott Liu 243918e2844SMichał Mirosław dev_err(&client->dev, 244918e2844SMichał Mirosław "(%s) I2C transfer failed: %pe\n", 245918e2844SMichał Mirosław cmd_name, ERR_PTR(ret)); 246918e2844SMichał Mirosław return ret; 247918e2844SMichał Mirosław } 248918e2844SMichał Mirosław 249918e2844SMichał Mirosław if (ret != ARRAY_SIZE(msgs) || 250918e2844SMichał Mirosław resp[FW_HDR_TYPE] != expected_response) { 251918e2844SMichał Mirosław if (--retries > 0) { 252918e2844SMichał Mirosław dev_dbg(&client->dev, 253918e2844SMichał Mirosław "(%s) unexpected response: %*ph (retrying)\n", 254918e2844SMichał Mirosław cmd_name, ret, resp); 255918e2844SMichał Mirosław continue; 256918e2844SMichał Mirosław } 257918e2844SMichał Mirosław 258918e2844SMichał Mirosław dev_err(&client->dev, 259918e2844SMichał Mirosław "(%s) unexpected response: %*ph\n", 260918e2844SMichał Mirosław cmd_name, ret, resp); 26166aee900SScott Liu return -EIO; 262918e2844SMichał Mirosław } 26366aee900SScott Liu 26466aee900SScott Liu return 0; 26566aee900SScott Liu } 266918e2844SMichał Mirosław } 26766aee900SScott Liu 26866aee900SScott Liu static int elants_i2c_calibrate(struct elants_data *ts) 26966aee900SScott Liu { 27066aee900SScott Liu struct i2c_client *client = ts->client; 27166aee900SScott Liu int ret, error; 27266aee900SScott Liu static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; 27366aee900SScott Liu static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; 27466aee900SScott Liu static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; 27566aee900SScott Liu 27666aee900SScott Liu disable_irq(client->irq); 27766aee900SScott Liu 27866aee900SScott Liu ts->state = ELAN_WAIT_RECALIBRATION; 27966aee900SScott Liu reinit_completion(&ts->cmd_done); 28066aee900SScott Liu 28166aee900SScott Liu elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); 28266aee900SScott Liu elants_i2c_send(client, rek, sizeof(rek)); 28366aee900SScott Liu 28466aee900SScott Liu enable_irq(client->irq); 28566aee900SScott Liu 28666aee900SScott Liu ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, 28766aee900SScott Liu msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); 28866aee900SScott Liu 28966aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 29066aee900SScott Liu 29166aee900SScott Liu if (ret <= 0) { 29266aee900SScott Liu error = ret < 0 ? ret : -ETIMEDOUT; 29366aee900SScott Liu dev_err(&client->dev, 29466aee900SScott Liu "error while waiting for calibration to complete: %d\n", 29566aee900SScott Liu error); 29666aee900SScott Liu return error; 29766aee900SScott Liu } 29866aee900SScott Liu 29966aee900SScott Liu if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { 30066aee900SScott Liu dev_err(&client->dev, 30166aee900SScott Liu "unexpected calibration response: %*ph\n", 30266aee900SScott Liu (int)sizeof(ts->cmd_resp), ts->cmd_resp); 30366aee900SScott Liu return -EINVAL; 30466aee900SScott Liu } 30566aee900SScott Liu 30666aee900SScott Liu return 0; 30766aee900SScott Liu } 30866aee900SScott Liu 30966aee900SScott Liu static int elants_i2c_sw_reset(struct i2c_client *client) 31066aee900SScott Liu { 31166aee900SScott Liu const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; 31266aee900SScott Liu int error; 31366aee900SScott Liu 31466aee900SScott Liu error = elants_i2c_send(client, soft_rst_cmd, 31566aee900SScott Liu sizeof(soft_rst_cmd)); 31666aee900SScott Liu if (error) { 31766aee900SScott Liu dev_err(&client->dev, "software reset failed: %d\n", error); 31866aee900SScott Liu return error; 31966aee900SScott Liu } 32066aee900SScott Liu 32166aee900SScott Liu /* 32266aee900SScott Liu * We should wait at least 10 msec (but no more than 40) before 32366aee900SScott Liu * sending fastboot or IAP command to the device. 32466aee900SScott Liu */ 32566aee900SScott Liu msleep(30); 32666aee900SScott Liu 32766aee900SScott Liu return 0; 32866aee900SScott Liu } 32966aee900SScott Liu 33066aee900SScott Liu static u16 elants_i2c_parse_version(u8 *buf) 33166aee900SScott Liu { 33266aee900SScott Liu return get_unaligned_be32(buf) >> 4; 33366aee900SScott Liu } 33466aee900SScott Liu 335bc1d57feSJohnny Chuang static int elants_i2c_query_hw_version(struct elants_data *ts) 33666aee900SScott Liu { 33766aee900SScott Liu struct i2c_client *client = ts->client; 338918e2844SMichał Mirosław int retry_cnt = MAX_RETRIES; 33966aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; 34066aee900SScott Liu u8 resp[HEADER_SIZE]; 341918e2844SMichał Mirosław int error; 34266aee900SScott Liu 343918e2844SMichał Mirosław while (retry_cnt--) { 34466aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 345918e2844SMichał Mirosław resp, sizeof(resp), 1, 346918e2844SMichał Mirosław "read fw id"); 347918e2844SMichał Mirosław if (error) 348918e2844SMichał Mirosław return error; 349918e2844SMichał Mirosław 35066aee900SScott Liu ts->hw_version = elants_i2c_parse_version(resp); 35166aee900SScott Liu if (ts->hw_version != 0xffff) 35266aee900SScott Liu return 0; 35366aee900SScott Liu } 35466aee900SScott Liu 355bc1d57feSJohnny Chuang dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); 35666aee900SScott Liu 35766aee900SScott Liu return -EINVAL; 35866aee900SScott Liu } 35966aee900SScott Liu 36066aee900SScott Liu static int elants_i2c_query_fw_version(struct elants_data *ts) 36166aee900SScott Liu { 36266aee900SScott Liu struct i2c_client *client = ts->client; 363918e2844SMichał Mirosław int retry_cnt = MAX_RETRIES; 36466aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; 36566aee900SScott Liu u8 resp[HEADER_SIZE]; 366918e2844SMichał Mirosław int error; 36766aee900SScott Liu 368918e2844SMichał Mirosław while (retry_cnt--) { 36966aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 370918e2844SMichał Mirosław resp, sizeof(resp), 1, 371918e2844SMichał Mirosław "read fw version"); 372918e2844SMichał Mirosław if (error) 373918e2844SMichał Mirosław return error; 374918e2844SMichał Mirosław 37566aee900SScott Liu ts->fw_version = elants_i2c_parse_version(resp); 376918e2844SMichał Mirosław if (ts->fw_version != 0x0000 && ts->fw_version != 0xffff) 37766aee900SScott Liu return 0; 378918e2844SMichał Mirosław 379918e2844SMichał Mirosław dev_dbg(&client->dev, "(read fw version) resp %*phC\n", 380918e2844SMichał Mirosław (int)sizeof(resp), resp); 38166aee900SScott Liu } 38266aee900SScott Liu 383918e2844SMichał Mirosław dev_err(&client->dev, "Invalid fw ver: %#04x\n", ts->fw_version); 38466aee900SScott Liu 38566aee900SScott Liu return -EINVAL; 38666aee900SScott Liu } 38766aee900SScott Liu 38866aee900SScott Liu static int elants_i2c_query_test_version(struct elants_data *ts) 38966aee900SScott Liu { 39066aee900SScott Liu struct i2c_client *client = ts->client; 391918e2844SMichał Mirosław int error; 39266aee900SScott Liu u16 version; 39366aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; 39466aee900SScott Liu u8 resp[HEADER_SIZE]; 39566aee900SScott Liu 39666aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 397918e2844SMichał Mirosław resp, sizeof(resp), MAX_RETRIES, 398918e2844SMichał Mirosław "read test version"); 399918e2844SMichał Mirosław if (error) { 400918e2844SMichał Mirosław dev_err(&client->dev, "Failed to read test version\n"); 401918e2844SMichał Mirosław return error; 402918e2844SMichał Mirosław } 403918e2844SMichał Mirosław 40466aee900SScott Liu version = elants_i2c_parse_version(resp); 40566aee900SScott Liu ts->test_version = version >> 8; 40666aee900SScott Liu ts->solution_version = version & 0xff; 40766aee900SScott Liu 40866aee900SScott Liu return 0; 40966aee900SScott Liu } 41066aee900SScott Liu 41166aee900SScott Liu static int elants_i2c_query_bc_version(struct elants_data *ts) 41266aee900SScott Liu { 41366aee900SScott Liu struct i2c_client *client = ts->client; 41466aee900SScott Liu const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; 41566aee900SScott Liu u8 resp[HEADER_SIZE]; 41666aee900SScott Liu u16 version; 41766aee900SScott Liu int error; 41866aee900SScott Liu 41966aee900SScott Liu error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 420918e2844SMichał Mirosław resp, sizeof(resp), 1, 421918e2844SMichał Mirosław "read BC version"); 422918e2844SMichał Mirosław if (error) 42366aee900SScott Liu return error; 42466aee900SScott Liu 42566aee900SScott Liu version = elants_i2c_parse_version(resp); 42666aee900SScott Liu ts->bc_version = version >> 8; 42766aee900SScott Liu ts->iap_version = version & 0xff; 42866aee900SScott Liu 42966aee900SScott Liu return 0; 43066aee900SScott Liu } 43166aee900SScott Liu 43266aee900SScott Liu static int elants_i2c_query_ts_info(struct elants_data *ts) 43366aee900SScott Liu { 43466aee900SScott Liu struct i2c_client *client = ts->client; 43566aee900SScott Liu int error; 43666aee900SScott Liu u8 resp[17]; 43766aee900SScott Liu u16 phy_x, phy_y, rows, cols, osr; 43866aee900SScott Liu const u8 get_resolution_cmd[] = { 43966aee900SScott Liu CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 44066aee900SScott Liu }; 44166aee900SScott Liu const u8 get_osr_cmd[] = { 44266aee900SScott Liu CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 44366aee900SScott Liu }; 44466aee900SScott Liu const u8 get_physical_scan_cmd[] = { 44566aee900SScott Liu CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 44666aee900SScott Liu }; 44766aee900SScott Liu const u8 get_physical_drive_cmd[] = { 44866aee900SScott Liu CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 44966aee900SScott Liu }; 45066aee900SScott Liu 45166aee900SScott Liu /* Get trace number */ 45266aee900SScott Liu error = elants_i2c_execute_command(client, 45366aee900SScott Liu get_resolution_cmd, 45466aee900SScott Liu sizeof(get_resolution_cmd), 455918e2844SMichał Mirosław resp, sizeof(resp), 1, 456918e2844SMichał Mirosław "get resolution"); 457918e2844SMichał Mirosław if (error) 45866aee900SScott Liu return error; 45966aee900SScott Liu 46066aee900SScott Liu rows = resp[2] + resp[6] + resp[10]; 46166aee900SScott Liu cols = resp[3] + resp[7] + resp[11]; 46266aee900SScott Liu 4634238e52cSJohnny Chuang /* Get report resolution value of ABS_MT_TOUCH_MAJOR */ 4644238e52cSJohnny Chuang ts->major_res = resp[16]; 4654238e52cSJohnny Chuang 46666aee900SScott Liu /* Process mm_to_pixel information */ 46766aee900SScott Liu error = elants_i2c_execute_command(client, 46866aee900SScott Liu get_osr_cmd, sizeof(get_osr_cmd), 469918e2844SMichał Mirosław resp, sizeof(resp), 1, "get osr"); 470918e2844SMichał Mirosław if (error) 47166aee900SScott Liu return error; 47266aee900SScott Liu 47366aee900SScott Liu osr = resp[3]; 47466aee900SScott Liu 47566aee900SScott Liu error = elants_i2c_execute_command(client, 47666aee900SScott Liu get_physical_scan_cmd, 47766aee900SScott Liu sizeof(get_physical_scan_cmd), 478918e2844SMichał Mirosław resp, sizeof(resp), 1, 479918e2844SMichał Mirosław "get physical scan"); 480918e2844SMichał Mirosław if (error) 48166aee900SScott Liu return error; 48266aee900SScott Liu 48366aee900SScott Liu phy_x = get_unaligned_be16(&resp[2]); 48466aee900SScott Liu 48566aee900SScott Liu error = elants_i2c_execute_command(client, 48666aee900SScott Liu get_physical_drive_cmd, 48766aee900SScott Liu sizeof(get_physical_drive_cmd), 488918e2844SMichał Mirosław resp, sizeof(resp), 1, 489918e2844SMichał Mirosław "get physical drive"); 490918e2844SMichał Mirosław if (error) 49166aee900SScott Liu return error; 49266aee900SScott Liu 49366aee900SScott Liu phy_y = get_unaligned_be16(&resp[2]); 49466aee900SScott Liu 49566aee900SScott Liu dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); 49666aee900SScott Liu 49766aee900SScott Liu if (rows == 0 || cols == 0 || osr == 0) { 49866aee900SScott Liu dev_warn(&client->dev, 49966aee900SScott Liu "invalid trace number data: %d, %d, %d\n", 50066aee900SScott Liu rows, cols, osr); 50166aee900SScott Liu } else { 50266aee900SScott Liu /* translate trace number to TS resolution */ 50366aee900SScott Liu ts->x_max = ELAN_TS_RESOLUTION(rows, osr); 50466aee900SScott Liu ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); 50566aee900SScott Liu ts->y_max = ELAN_TS_RESOLUTION(cols, osr); 50666aee900SScott Liu ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); 50766aee900SScott Liu } 50866aee900SScott Liu 50966aee900SScott Liu return 0; 51066aee900SScott Liu } 51166aee900SScott Liu 51266aee900SScott Liu static int elants_i2c_fastboot(struct i2c_client *client) 51366aee900SScott Liu { 51466aee900SScott Liu const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; 51566aee900SScott Liu int error; 51666aee900SScott Liu 51766aee900SScott Liu error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); 51866aee900SScott Liu if (error) { 51966aee900SScott Liu dev_err(&client->dev, "boot failed: %d\n", error); 52066aee900SScott Liu return error; 52166aee900SScott Liu } 52266aee900SScott Liu 52366aee900SScott Liu dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); 52466aee900SScott Liu return 0; 52566aee900SScott Liu } 52666aee900SScott Liu 52766aee900SScott Liu static int elants_i2c_initialize(struct elants_data *ts) 52866aee900SScott Liu { 52966aee900SScott Liu struct i2c_client *client = ts->client; 530bc1d57feSJohnny Chuang int error, error2, retry_cnt; 53166aee900SScott Liu const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; 53266aee900SScott Liu const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; 53366aee900SScott Liu u8 buf[HEADER_SIZE]; 53466aee900SScott Liu 53566aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 53666aee900SScott Liu error = elants_i2c_sw_reset(client); 53766aee900SScott Liu if (error) { 53866aee900SScott Liu /* Continue initializing if it's the last try */ 53966aee900SScott Liu if (retry_cnt < MAX_RETRIES - 1) 54066aee900SScott Liu continue; 54166aee900SScott Liu } 54266aee900SScott Liu 54366aee900SScott Liu error = elants_i2c_fastboot(client); 54466aee900SScott Liu if (error) { 54566aee900SScott Liu /* Continue initializing if it's the last try */ 54666aee900SScott Liu if (retry_cnt < MAX_RETRIES - 1) 54766aee900SScott Liu continue; 54866aee900SScott Liu } 54966aee900SScott Liu 55066aee900SScott Liu /* Wait for Hello packet */ 55166aee900SScott Liu msleep(BOOT_TIME_DELAY_MS); 55266aee900SScott Liu 55366aee900SScott Liu error = elants_i2c_read(client, buf, sizeof(buf)); 55466aee900SScott Liu if (error) { 55566aee900SScott Liu dev_err(&client->dev, 55666aee900SScott Liu "failed to read 'hello' packet: %d\n", error); 55766aee900SScott Liu } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { 55866aee900SScott Liu ts->iap_mode = ELAN_IAP_OPERATIONAL; 55966aee900SScott Liu break; 56066aee900SScott Liu } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { 56166aee900SScott Liu /* 56266aee900SScott Liu * Setting error code will mark device 56366aee900SScott Liu * in recovery mode below. 56466aee900SScott Liu */ 56566aee900SScott Liu error = -EIO; 56666aee900SScott Liu break; 56766aee900SScott Liu } else { 56866aee900SScott Liu error = -EINVAL; 56966aee900SScott Liu dev_err(&client->dev, 57066aee900SScott Liu "invalid 'hello' packet: %*ph\n", 57166aee900SScott Liu (int)sizeof(buf), buf); 57266aee900SScott Liu } 57366aee900SScott Liu } 57466aee900SScott Liu 575bc1d57feSJohnny Chuang /* hw version is available even if device in recovery state */ 576bc1d57feSJohnny Chuang error2 = elants_i2c_query_hw_version(ts); 577f0b57e19SJohnny.Chuang if (!error2) 578f0b57e19SJohnny.Chuang error2 = elants_i2c_query_bc_version(ts); 57966aee900SScott Liu if (!error) 580bc1d57feSJohnny Chuang error = error2; 581bc1d57feSJohnny Chuang 58266aee900SScott Liu if (!error) 58366aee900SScott Liu error = elants_i2c_query_fw_version(ts); 584bc1d57feSJohnny Chuang if (!error) 585bc1d57feSJohnny Chuang error = elants_i2c_query_test_version(ts); 586bc1d57feSJohnny Chuang if (!error) 587bc1d57feSJohnny Chuang error = elants_i2c_query_ts_info(ts); 58866aee900SScott Liu 589bc1d57feSJohnny Chuang if (error) 59066aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 59166aee900SScott Liu 59266aee900SScott Liu return 0; 59366aee900SScott Liu } 59466aee900SScott Liu 59566aee900SScott Liu /* 59666aee900SScott Liu * Firmware update interface. 59766aee900SScott Liu */ 59866aee900SScott Liu 59966aee900SScott Liu static int elants_i2c_fw_write_page(struct i2c_client *client, 60066aee900SScott Liu const void *page) 60166aee900SScott Liu { 60266aee900SScott Liu const u8 ack_ok[] = { 0xaa, 0xaa }; 60366aee900SScott Liu u8 buf[2]; 60466aee900SScott Liu int retry; 60566aee900SScott Liu int error; 60666aee900SScott Liu 60766aee900SScott Liu for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { 60866aee900SScott Liu error = elants_i2c_send(client, page, ELAN_FW_PAGESIZE); 60966aee900SScott Liu if (error) { 61066aee900SScott Liu dev_err(&client->dev, 61166aee900SScott Liu "IAP Write Page failed: %d\n", error); 61266aee900SScott Liu continue; 61366aee900SScott Liu } 61466aee900SScott Liu 61566aee900SScott Liu error = elants_i2c_read(client, buf, 2); 61666aee900SScott Liu if (error) { 61766aee900SScott Liu dev_err(&client->dev, 61866aee900SScott Liu "IAP Ack read failed: %d\n", error); 61966aee900SScott Liu return error; 62066aee900SScott Liu } 62166aee900SScott Liu 62266aee900SScott Liu if (!memcmp(buf, ack_ok, sizeof(ack_ok))) 62366aee900SScott Liu return 0; 62466aee900SScott Liu 62566aee900SScott Liu error = -EIO; 62666aee900SScott Liu dev_err(&client->dev, 62766aee900SScott Liu "IAP Get Ack Error [%02x:%02x]\n", 62866aee900SScott Liu buf[0], buf[1]); 62966aee900SScott Liu } 63066aee900SScott Liu 63166aee900SScott Liu return error; 63266aee900SScott Liu } 63366aee900SScott Liu 634f0b57e19SJohnny.Chuang static int elants_i2c_validate_remark_id(struct elants_data *ts, 635f0b57e19SJohnny.Chuang const struct firmware *fw) 636f0b57e19SJohnny.Chuang { 637f0b57e19SJohnny.Chuang struct i2c_client *client = ts->client; 638f0b57e19SJohnny.Chuang int error; 639f0b57e19SJohnny.Chuang const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 }; 640f0b57e19SJohnny.Chuang u8 resp[6] = { 0 }; 641f0b57e19SJohnny.Chuang u16 ts_remark_id = 0; 642f0b57e19SJohnny.Chuang u16 fw_remark_id = 0; 643f0b57e19SJohnny.Chuang 644f0b57e19SJohnny.Chuang /* Compare TS Remark ID and FW Remark ID */ 645f0b57e19SJohnny.Chuang error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 646918e2844SMichał Mirosław resp, sizeof(resp), 647918e2844SMichał Mirosław 1, "read Remark ID"); 648918e2844SMichał Mirosław if (error) 649f0b57e19SJohnny.Chuang return error; 650f0b57e19SJohnny.Chuang 651f0b57e19SJohnny.Chuang ts_remark_id = get_unaligned_be16(&resp[3]); 652f0b57e19SJohnny.Chuang 653f0b57e19SJohnny.Chuang fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]); 654f0b57e19SJohnny.Chuang 655f0b57e19SJohnny.Chuang if (fw_remark_id != ts_remark_id) { 656f0b57e19SJohnny.Chuang dev_err(&client->dev, 657f0b57e19SJohnny.Chuang "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n", 658f0b57e19SJohnny.Chuang ts_remark_id, fw_remark_id); 659f0b57e19SJohnny.Chuang return -EINVAL; 660f0b57e19SJohnny.Chuang } 661f0b57e19SJohnny.Chuang 662f0b57e19SJohnny.Chuang return 0; 663f0b57e19SJohnny.Chuang } 664f0b57e19SJohnny.Chuang 66566aee900SScott Liu static int elants_i2c_do_update_firmware(struct i2c_client *client, 66666aee900SScott Liu const struct firmware *fw, 66766aee900SScott Liu bool force) 66866aee900SScott Liu { 669f0b57e19SJohnny.Chuang struct elants_data *ts = i2c_get_clientdata(client); 67066aee900SScott Liu const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; 67166aee900SScott Liu const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; 67266aee900SScott Liu const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; 6736fd38502SJames Chen const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 }; 67466aee900SScott Liu u8 buf[HEADER_SIZE]; 67566aee900SScott Liu u16 send_id; 67666aee900SScott Liu int page, n_fw_pages; 67766aee900SScott Liu int error; 678f0b57e19SJohnny.Chuang bool check_remark_id = ts->iap_version >= 0x60; 67966aee900SScott Liu 68066aee900SScott Liu /* Recovery mode detection! */ 68166aee900SScott Liu if (force) { 68266aee900SScott Liu dev_dbg(&client->dev, "Recovery mode procedure\n"); 683f0b57e19SJohnny.Chuang 684f0b57e19SJohnny.Chuang if (check_remark_id) { 685f0b57e19SJohnny.Chuang error = elants_i2c_validate_remark_id(ts, fw); 686f0b57e19SJohnny.Chuang if (error) 687f0b57e19SJohnny.Chuang return error; 688f0b57e19SJohnny.Chuang } 689f0b57e19SJohnny.Chuang 69066aee900SScott Liu error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); 691f0b57e19SJohnny.Chuang if (error) { 692f0b57e19SJohnny.Chuang dev_err(&client->dev, "failed to enter IAP mode: %d\n", 693f0b57e19SJohnny.Chuang error); 694f0b57e19SJohnny.Chuang return error; 695f0b57e19SJohnny.Chuang } 69666aee900SScott Liu } else { 69766aee900SScott Liu /* Start IAP Procedure */ 69866aee900SScott Liu dev_dbg(&client->dev, "Normal IAP procedure\n"); 699f0b57e19SJohnny.Chuang 7006fd38502SJames Chen /* Close idle mode */ 7016fd38502SJames Chen error = elants_i2c_send(client, close_idle, sizeof(close_idle)); 7026fd38502SJames Chen if (error) 7036fd38502SJames Chen dev_err(&client->dev, "Failed close idle: %d\n", error); 7046fd38502SJames Chen msleep(60); 705f0b57e19SJohnny.Chuang 70666aee900SScott Liu elants_i2c_sw_reset(client); 7076fd38502SJames Chen msleep(20); 708f0b57e19SJohnny.Chuang 709f0b57e19SJohnny.Chuang if (check_remark_id) { 710f0b57e19SJohnny.Chuang error = elants_i2c_validate_remark_id(ts, fw); 711f0b57e19SJohnny.Chuang if (error) 712f0b57e19SJohnny.Chuang return error; 71366aee900SScott Liu } 71466aee900SScott Liu 715f0b57e19SJohnny.Chuang error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); 71666aee900SScott Liu if (error) { 717f0b57e19SJohnny.Chuang dev_err(&client->dev, "failed to enter IAP mode: %d\n", 718f0b57e19SJohnny.Chuang error); 71966aee900SScott Liu return error; 72066aee900SScott Liu } 721f0b57e19SJohnny.Chuang } 72266aee900SScott Liu 72366aee900SScott Liu msleep(20); 72466aee900SScott Liu 72566aee900SScott Liu /* check IAP state */ 72666aee900SScott Liu error = elants_i2c_read(client, buf, 4); 72766aee900SScott Liu if (error) { 72866aee900SScott Liu dev_err(&client->dev, 72966aee900SScott Liu "failed to read IAP acknowledgement: %d\n", 73066aee900SScott Liu error); 73166aee900SScott Liu return error; 73266aee900SScott Liu } 73366aee900SScott Liu 73466aee900SScott Liu if (memcmp(buf, iap_ack, sizeof(iap_ack))) { 73566aee900SScott Liu dev_err(&client->dev, 73666aee900SScott Liu "failed to enter IAP: %*ph (expected %*ph)\n", 73766aee900SScott Liu (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); 73866aee900SScott Liu return -EIO; 73966aee900SScott Liu } 74066aee900SScott Liu 74166aee900SScott Liu dev_info(&client->dev, "successfully entered IAP mode"); 74266aee900SScott Liu 74366aee900SScott Liu send_id = client->addr; 74466aee900SScott Liu error = elants_i2c_send(client, &send_id, 1); 74566aee900SScott Liu if (error) { 74666aee900SScott Liu dev_err(&client->dev, "sending dummy byte failed: %d\n", 74766aee900SScott Liu error); 74866aee900SScott Liu return error; 74966aee900SScott Liu } 75066aee900SScott Liu 75166aee900SScott Liu /* Clear the last page of Master */ 75266aee900SScott Liu error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); 75366aee900SScott Liu if (error) { 75466aee900SScott Liu dev_err(&client->dev, "clearing of the last page failed: %d\n", 75566aee900SScott Liu error); 75666aee900SScott Liu return error; 75766aee900SScott Liu } 75866aee900SScott Liu 75966aee900SScott Liu error = elants_i2c_read(client, buf, 2); 76066aee900SScott Liu if (error) { 76166aee900SScott Liu dev_err(&client->dev, 76266aee900SScott Liu "failed to read ACK for clearing the last page: %d\n", 76366aee900SScott Liu error); 76466aee900SScott Liu return error; 76566aee900SScott Liu } 76666aee900SScott Liu 76766aee900SScott Liu n_fw_pages = fw->size / ELAN_FW_PAGESIZE; 76866aee900SScott Liu dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); 76966aee900SScott Liu 77066aee900SScott Liu for (page = 0; page < n_fw_pages; page++) { 77166aee900SScott Liu error = elants_i2c_fw_write_page(client, 77266aee900SScott Liu fw->data + page * ELAN_FW_PAGESIZE); 77366aee900SScott Liu if (error) { 77466aee900SScott Liu dev_err(&client->dev, 77566aee900SScott Liu "failed to write FW page %d: %d\n", 77666aee900SScott Liu page, error); 77766aee900SScott Liu return error; 77866aee900SScott Liu } 77966aee900SScott Liu } 78066aee900SScott Liu 78166aee900SScott Liu /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ 78266aee900SScott Liu msleep(300); 78366aee900SScott Liu 78466aee900SScott Liu dev_info(&client->dev, "firmware update completed\n"); 78566aee900SScott Liu return 0; 78666aee900SScott Liu } 78766aee900SScott Liu 78866aee900SScott Liu static int elants_i2c_fw_update(struct elants_data *ts) 78966aee900SScott Liu { 79066aee900SScott Liu struct i2c_client *client = ts->client; 79166aee900SScott Liu const struct firmware *fw; 79237dee1acSCharlie Mooney char *fw_name; 79366aee900SScott Liu int error; 79466aee900SScott Liu 7958c0776a8SDmitry Torokhov fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); 79637dee1acSCharlie Mooney if (!fw_name) 79737dee1acSCharlie Mooney return -ENOMEM; 79837dee1acSCharlie Mooney 79937dee1acSCharlie Mooney dev_info(&client->dev, "requesting fw name = %s\n", fw_name); 80037dee1acSCharlie Mooney error = request_firmware(&fw, fw_name, &client->dev); 80137dee1acSCharlie Mooney kfree(fw_name); 80266aee900SScott Liu if (error) { 80337dee1acSCharlie Mooney dev_err(&client->dev, "failed to request firmware: %d\n", 80437dee1acSCharlie Mooney error); 80566aee900SScott Liu return error; 80666aee900SScott Liu } 80766aee900SScott Liu 80866aee900SScott Liu if (fw->size % ELAN_FW_PAGESIZE) { 80966aee900SScott Liu dev_err(&client->dev, "invalid firmware length: %zu\n", 81066aee900SScott Liu fw->size); 81166aee900SScott Liu error = -EINVAL; 81266aee900SScott Liu goto out; 81366aee900SScott Liu } 81466aee900SScott Liu 81566aee900SScott Liu disable_irq(client->irq); 81666aee900SScott Liu 81766aee900SScott Liu error = elants_i2c_do_update_firmware(client, fw, 81866aee900SScott Liu ts->iap_mode == ELAN_IAP_RECOVERY); 81966aee900SScott Liu if (error) { 82066aee900SScott Liu dev_err(&client->dev, "firmware update failed: %d\n", error); 82166aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 82266aee900SScott Liu goto out_enable_irq; 82366aee900SScott Liu } 82466aee900SScott Liu 82566aee900SScott Liu error = elants_i2c_initialize(ts); 82666aee900SScott Liu if (error) { 82766aee900SScott Liu dev_err(&client->dev, 82866aee900SScott Liu "failed to initialize device after firmware update: %d\n", 82966aee900SScott Liu error); 83066aee900SScott Liu ts->iap_mode = ELAN_IAP_RECOVERY; 83166aee900SScott Liu goto out_enable_irq; 83266aee900SScott Liu } 83366aee900SScott Liu 83466aee900SScott Liu ts->iap_mode = ELAN_IAP_OPERATIONAL; 83566aee900SScott Liu 83666aee900SScott Liu out_enable_irq: 83766aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 83866aee900SScott Liu enable_irq(client->irq); 83966aee900SScott Liu msleep(100); 84066aee900SScott Liu 84166aee900SScott Liu if (!error) 84266aee900SScott Liu elants_i2c_calibrate(ts); 84366aee900SScott Liu out: 84466aee900SScott Liu release_firmware(fw); 84566aee900SScott Liu return error; 84666aee900SScott Liu } 84766aee900SScott Liu 84866aee900SScott Liu /* 84966aee900SScott Liu * Event reporting. 85066aee900SScott Liu */ 85166aee900SScott Liu 85266aee900SScott Liu static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) 85366aee900SScott Liu { 85466aee900SScott Liu struct input_dev *input = ts->input; 85566aee900SScott Liu unsigned int n_fingers; 856f27ad893SJohnny Chuang unsigned int tool_type; 85766aee900SScott Liu u16 finger_state; 85866aee900SScott Liu int i; 85966aee900SScott Liu 86066aee900SScott Liu n_fingers = buf[FW_POS_STATE + 1] & 0x0f; 86166aee900SScott Liu finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | 86266aee900SScott Liu buf[FW_POS_STATE]; 86366aee900SScott Liu 86466aee900SScott Liu dev_dbg(&ts->client->dev, 86566aee900SScott Liu "n_fingers: %u, state: %04x\n", n_fingers, finger_state); 86666aee900SScott Liu 867f27ad893SJohnny Chuang /* Note: all fingers have the same tool type */ 868f27ad893SJohnny Chuang tool_type = buf[FW_POS_TOOL_TYPE] & BIT(0) ? 869f27ad893SJohnny Chuang MT_TOOL_FINGER : MT_TOOL_PALM; 870f27ad893SJohnny Chuang 87166aee900SScott Liu for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { 87266aee900SScott Liu if (finger_state & 1) { 87366aee900SScott Liu unsigned int x, y, p, w; 87466aee900SScott Liu u8 *pos; 87566aee900SScott Liu 87666aee900SScott Liu pos = &buf[FW_POS_XY + i * 3]; 87766aee900SScott Liu x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; 87866aee900SScott Liu y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; 87966aee900SScott Liu p = buf[FW_POS_PRESSURE + i]; 88066aee900SScott Liu w = buf[FW_POS_WIDTH + i]; 88166aee900SScott Liu 88266aee900SScott Liu dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", 88366aee900SScott Liu i, x, y, p, w); 88466aee900SScott Liu 88566aee900SScott Liu input_mt_slot(input, i); 886f27ad893SJohnny Chuang input_mt_report_slot_state(input, tool_type, true); 88768334dbaSMichał Mirosław touchscreen_report_pos(input, &ts->prop, x, y, true); 88866aee900SScott Liu input_event(input, EV_ABS, ABS_MT_PRESSURE, p); 88966aee900SScott Liu input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); 89066aee900SScott Liu 89166aee900SScott Liu n_fingers--; 89266aee900SScott Liu } 89366aee900SScott Liu 89466aee900SScott Liu finger_state >>= 1; 89566aee900SScott Liu } 89666aee900SScott Liu 89766aee900SScott Liu input_mt_sync_frame(input); 89866aee900SScott Liu input_sync(input); 89966aee900SScott Liu } 90066aee900SScott Liu 90166aee900SScott Liu static u8 elants_i2c_calculate_checksum(u8 *buf) 90266aee900SScott Liu { 90366aee900SScott Liu u8 checksum = 0; 90466aee900SScott Liu u8 i; 90566aee900SScott Liu 90666aee900SScott Liu for (i = 0; i < FW_POS_CHECKSUM; i++) 90766aee900SScott Liu checksum += buf[i]; 90866aee900SScott Liu 90966aee900SScott Liu return checksum; 91066aee900SScott Liu } 91166aee900SScott Liu 91266aee900SScott Liu static void elants_i2c_event(struct elants_data *ts, u8 *buf) 91366aee900SScott Liu { 91466aee900SScott Liu u8 checksum = elants_i2c_calculate_checksum(buf); 91566aee900SScott Liu 91666aee900SScott Liu if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) 91766aee900SScott Liu dev_warn(&ts->client->dev, 91866aee900SScott Liu "%s: invalid checksum for packet %02x: %02x vs. %02x\n", 91966aee900SScott Liu __func__, buf[FW_POS_HEADER], 92066aee900SScott Liu checksum, buf[FW_POS_CHECKSUM]); 92166aee900SScott Liu else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) 92266aee900SScott Liu dev_warn(&ts->client->dev, 92366aee900SScott Liu "%s: unknown packet type: %02x\n", 92466aee900SScott Liu __func__, buf[FW_POS_HEADER]); 92566aee900SScott Liu else 92666aee900SScott Liu elants_i2c_mt_event(ts, buf); 92766aee900SScott Liu } 92866aee900SScott Liu 92966aee900SScott Liu static irqreturn_t elants_i2c_irq(int irq, void *_dev) 93066aee900SScott Liu { 93166aee900SScott Liu const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; 93266aee900SScott Liu struct elants_data *ts = _dev; 93366aee900SScott Liu struct i2c_client *client = ts->client; 93466aee900SScott Liu int report_count, report_len; 93566aee900SScott Liu int i; 93666aee900SScott Liu int len; 93766aee900SScott Liu 93800f73f97SStephen Boyd len = i2c_master_recv_dmasafe(client, ts->buf, sizeof(ts->buf)); 93966aee900SScott Liu if (len < 0) { 94066aee900SScott Liu dev_err(&client->dev, "%s: failed to read data: %d\n", 94166aee900SScott Liu __func__, len); 94266aee900SScott Liu goto out; 94366aee900SScott Liu } 94466aee900SScott Liu 94566aee900SScott Liu dev_dbg(&client->dev, "%s: packet %*ph\n", 94666aee900SScott Liu __func__, HEADER_SIZE, ts->buf); 94766aee900SScott Liu 94866aee900SScott Liu switch (ts->state) { 94966aee900SScott Liu case ELAN_WAIT_RECALIBRATION: 95066aee900SScott Liu if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { 95166aee900SScott Liu memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); 95266aee900SScott Liu complete(&ts->cmd_done); 95366aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 95466aee900SScott Liu } 95566aee900SScott Liu break; 95666aee900SScott Liu 95766aee900SScott Liu case ELAN_WAIT_QUEUE_HEADER: 95866aee900SScott Liu if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) 95966aee900SScott Liu break; 96066aee900SScott Liu 96166aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 9626f49c4f5SGustavo A. R. Silva fallthrough; 96366aee900SScott Liu 96466aee900SScott Liu case ELAN_STATE_NORMAL: 96566aee900SScott Liu 96666aee900SScott Liu switch (ts->buf[FW_HDR_TYPE]) { 96766aee900SScott Liu case CMD_HEADER_HELLO: 96866aee900SScott Liu case CMD_HEADER_RESP: 96966aee900SScott Liu case CMD_HEADER_REK: 97066aee900SScott Liu break; 97166aee900SScott Liu 97266aee900SScott Liu case QUEUE_HEADER_WAIT: 97366aee900SScott Liu if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { 97466aee900SScott Liu dev_err(&client->dev, 97566aee900SScott Liu "invalid wait packet %*ph\n", 97666aee900SScott Liu HEADER_SIZE, ts->buf); 97766aee900SScott Liu } else { 97866aee900SScott Liu ts->state = ELAN_WAIT_QUEUE_HEADER; 97966aee900SScott Liu udelay(30); 98066aee900SScott Liu } 98166aee900SScott Liu break; 98266aee900SScott Liu 98366aee900SScott Liu case QUEUE_HEADER_SINGLE: 98466aee900SScott Liu elants_i2c_event(ts, &ts->buf[HEADER_SIZE]); 98566aee900SScott Liu break; 98666aee900SScott Liu 98766aee900SScott Liu case QUEUE_HEADER_NORMAL: 98866aee900SScott Liu report_count = ts->buf[FW_HDR_COUNT]; 9891c3415a0SGuenter Roeck if (report_count == 0 || report_count > 3) { 99066aee900SScott Liu dev_err(&client->dev, 9911c3415a0SGuenter Roeck "bad report count: %*ph\n", 99266aee900SScott Liu HEADER_SIZE, ts->buf); 99366aee900SScott Liu break; 99466aee900SScott Liu } 99566aee900SScott Liu 99666aee900SScott Liu report_len = ts->buf[FW_HDR_LENGTH] / report_count; 99766aee900SScott Liu if (report_len != PACKET_SIZE) { 99866aee900SScott Liu dev_err(&client->dev, 99966aee900SScott Liu "mismatching report length: %*ph\n", 100066aee900SScott Liu HEADER_SIZE, ts->buf); 100166aee900SScott Liu break; 100266aee900SScott Liu } 100366aee900SScott Liu 100466aee900SScott Liu for (i = 0; i < report_count; i++) { 100566aee900SScott Liu u8 *buf = ts->buf + HEADER_SIZE + 100666aee900SScott Liu i * PACKET_SIZE; 100766aee900SScott Liu elants_i2c_event(ts, buf); 100866aee900SScott Liu } 100966aee900SScott Liu break; 101066aee900SScott Liu 101166aee900SScott Liu default: 101266aee900SScott Liu dev_err(&client->dev, "unknown packet %*ph\n", 101366aee900SScott Liu HEADER_SIZE, ts->buf); 101466aee900SScott Liu break; 101566aee900SScott Liu } 101666aee900SScott Liu break; 101766aee900SScott Liu } 101866aee900SScott Liu 101966aee900SScott Liu out: 102066aee900SScott Liu return IRQ_HANDLED; 102166aee900SScott Liu } 102266aee900SScott Liu 102366aee900SScott Liu /* 102466aee900SScott Liu * sysfs interface 102566aee900SScott Liu */ 102666aee900SScott Liu static ssize_t calibrate_store(struct device *dev, 102766aee900SScott Liu struct device_attribute *attr, 102866aee900SScott Liu const char *buf, size_t count) 102966aee900SScott Liu { 103066aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 103166aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 103266aee900SScott Liu int error; 103366aee900SScott Liu 103466aee900SScott Liu error = mutex_lock_interruptible(&ts->sysfs_mutex); 103566aee900SScott Liu if (error) 103666aee900SScott Liu return error; 103766aee900SScott Liu 103866aee900SScott Liu error = elants_i2c_calibrate(ts); 103966aee900SScott Liu 104066aee900SScott Liu mutex_unlock(&ts->sysfs_mutex); 104166aee900SScott Liu return error ?: count; 104266aee900SScott Liu } 104366aee900SScott Liu 104466aee900SScott Liu static ssize_t write_update_fw(struct device *dev, 104566aee900SScott Liu struct device_attribute *attr, 104666aee900SScott Liu const char *buf, size_t count) 104766aee900SScott Liu { 104866aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 104966aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 105066aee900SScott Liu int error; 105166aee900SScott Liu 105266aee900SScott Liu error = mutex_lock_interruptible(&ts->sysfs_mutex); 105366aee900SScott Liu if (error) 105466aee900SScott Liu return error; 105566aee900SScott Liu 105666aee900SScott Liu error = elants_i2c_fw_update(ts); 105766aee900SScott Liu dev_dbg(dev, "firmware update result: %d\n", error); 105866aee900SScott Liu 105966aee900SScott Liu mutex_unlock(&ts->sysfs_mutex); 106066aee900SScott Liu return error ?: count; 106166aee900SScott Liu } 106266aee900SScott Liu 106366aee900SScott Liu static ssize_t show_iap_mode(struct device *dev, 106466aee900SScott Liu struct device_attribute *attr, char *buf) 106566aee900SScott Liu { 106666aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 106766aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 106866aee900SScott Liu 106966aee900SScott Liu return sprintf(buf, "%s\n", 107066aee900SScott Liu ts->iap_mode == ELAN_IAP_OPERATIONAL ? 107166aee900SScott Liu "Normal" : "Recovery"); 107266aee900SScott Liu } 107366aee900SScott Liu 1074cf520c64SJohnny Chuang static ssize_t show_calibration_count(struct device *dev, 1075cf520c64SJohnny Chuang struct device_attribute *attr, char *buf) 1076cf520c64SJohnny Chuang { 1077cf520c64SJohnny Chuang struct i2c_client *client = to_i2c_client(dev); 1078cf520c64SJohnny Chuang const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_REK, 0x00, 0x01 }; 1079cf520c64SJohnny Chuang u8 resp[HEADER_SIZE]; 1080cf520c64SJohnny Chuang u16 rek_count; 1081cf520c64SJohnny Chuang int error; 1082cf520c64SJohnny Chuang 1083cf520c64SJohnny Chuang error = elants_i2c_execute_command(client, cmd, sizeof(cmd), 1084918e2844SMichał Mirosław resp, sizeof(resp), 1, 1085918e2844SMichał Mirosław "read ReK status"); 1086918e2844SMichał Mirosław if (error) 1087cf520c64SJohnny Chuang return sprintf(buf, "%d\n", error); 1088cf520c64SJohnny Chuang 1089cf520c64SJohnny Chuang rek_count = get_unaligned_be16(&resp[2]); 1090cf520c64SJohnny Chuang return sprintf(buf, "0x%04x\n", rek_count); 1091cf520c64SJohnny Chuang } 1092cf520c64SJohnny Chuang 10936cbaefb4SJoe Perches static DEVICE_ATTR_WO(calibrate); 109466aee900SScott Liu static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL); 1095cf520c64SJohnny Chuang static DEVICE_ATTR(calibration_count, S_IRUGO, show_calibration_count, NULL); 109666aee900SScott Liu static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw); 109766aee900SScott Liu 109866aee900SScott Liu struct elants_version_attribute { 109966aee900SScott Liu struct device_attribute dattr; 110066aee900SScott Liu size_t field_offset; 110166aee900SScott Liu size_t field_size; 110266aee900SScott Liu }; 110366aee900SScott Liu 110466aee900SScott Liu #define __ELANTS_FIELD_SIZE(_field) \ 110566aee900SScott Liu sizeof(((struct elants_data *)NULL)->_field) 110666aee900SScott Liu #define __ELANTS_VERIFY_SIZE(_field) \ 110766aee900SScott Liu (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ 110866aee900SScott Liu __ELANTS_FIELD_SIZE(_field)) 110966aee900SScott Liu #define ELANTS_VERSION_ATTR(_field) \ 111066aee900SScott Liu struct elants_version_attribute elants_ver_attr_##_field = { \ 111166aee900SScott Liu .dattr = __ATTR(_field, S_IRUGO, \ 111266aee900SScott Liu elants_version_attribute_show, NULL), \ 111366aee900SScott Liu .field_offset = offsetof(struct elants_data, _field), \ 111466aee900SScott Liu .field_size = __ELANTS_VERIFY_SIZE(_field), \ 111566aee900SScott Liu } 111666aee900SScott Liu 111766aee900SScott Liu static ssize_t elants_version_attribute_show(struct device *dev, 111866aee900SScott Liu struct device_attribute *dattr, 111966aee900SScott Liu char *buf) 112066aee900SScott Liu { 112166aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 112266aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 112366aee900SScott Liu struct elants_version_attribute *attr = 112466aee900SScott Liu container_of(dattr, struct elants_version_attribute, dattr); 112566aee900SScott Liu u8 *field = (u8 *)((char *)ts + attr->field_offset); 112666aee900SScott Liu unsigned int fmt_size; 112766aee900SScott Liu unsigned int val; 112866aee900SScott Liu 112966aee900SScott Liu if (attr->field_size == 1) { 113066aee900SScott Liu val = *field; 113166aee900SScott Liu fmt_size = 2; /* 2 HEX digits */ 113266aee900SScott Liu } else { 113366aee900SScott Liu val = *(u16 *)field; 113466aee900SScott Liu fmt_size = 4; /* 4 HEX digits */ 113566aee900SScott Liu } 113666aee900SScott Liu 113766aee900SScott Liu return sprintf(buf, "%0*x\n", fmt_size, val); 113866aee900SScott Liu } 113966aee900SScott Liu 114066aee900SScott Liu static ELANTS_VERSION_ATTR(fw_version); 114166aee900SScott Liu static ELANTS_VERSION_ATTR(hw_version); 114266aee900SScott Liu static ELANTS_VERSION_ATTR(test_version); 114366aee900SScott Liu static ELANTS_VERSION_ATTR(solution_version); 114466aee900SScott Liu static ELANTS_VERSION_ATTR(bc_version); 114566aee900SScott Liu static ELANTS_VERSION_ATTR(iap_version); 114666aee900SScott Liu 114766aee900SScott Liu static struct attribute *elants_attributes[] = { 114866aee900SScott Liu &dev_attr_calibrate.attr, 114966aee900SScott Liu &dev_attr_update_fw.attr, 115066aee900SScott Liu &dev_attr_iap_mode.attr, 1151cf520c64SJohnny Chuang &dev_attr_calibration_count.attr, 115266aee900SScott Liu 115366aee900SScott Liu &elants_ver_attr_fw_version.dattr.attr, 115466aee900SScott Liu &elants_ver_attr_hw_version.dattr.attr, 115566aee900SScott Liu &elants_ver_attr_test_version.dattr.attr, 115666aee900SScott Liu &elants_ver_attr_solution_version.dattr.attr, 115766aee900SScott Liu &elants_ver_attr_bc_version.dattr.attr, 115866aee900SScott Liu &elants_ver_attr_iap_version.dattr.attr, 115966aee900SScott Liu NULL 116066aee900SScott Liu }; 116166aee900SScott Liu 116248f960ddSArvind Yadav static const struct attribute_group elants_attribute_group = { 116366aee900SScott Liu .attrs = elants_attributes, 116466aee900SScott Liu }; 116566aee900SScott Liu 1166afe10358SDmitry Torokhov static int elants_i2c_power_on(struct elants_data *ts) 1167afe10358SDmitry Torokhov { 1168afe10358SDmitry Torokhov int error; 1169afe10358SDmitry Torokhov 1170afe10358SDmitry Torokhov /* 1171afe10358SDmitry Torokhov * If we do not have reset gpio assume platform firmware 1172afe10358SDmitry Torokhov * controls regulators and does power them on for us. 1173afe10358SDmitry Torokhov */ 1174afe10358SDmitry Torokhov if (IS_ERR_OR_NULL(ts->reset_gpio)) 1175afe10358SDmitry Torokhov return 0; 1176afe10358SDmitry Torokhov 1177afe10358SDmitry Torokhov gpiod_set_value_cansleep(ts->reset_gpio, 1); 1178afe10358SDmitry Torokhov 1179afe10358SDmitry Torokhov error = regulator_enable(ts->vcc33); 1180afe10358SDmitry Torokhov if (error) { 1181afe10358SDmitry Torokhov dev_err(&ts->client->dev, 1182afe10358SDmitry Torokhov "failed to enable vcc33 regulator: %d\n", 1183afe10358SDmitry Torokhov error); 1184afe10358SDmitry Torokhov goto release_reset_gpio; 1185afe10358SDmitry Torokhov } 1186afe10358SDmitry Torokhov 1187afe10358SDmitry Torokhov error = regulator_enable(ts->vccio); 1188afe10358SDmitry Torokhov if (error) { 1189afe10358SDmitry Torokhov dev_err(&ts->client->dev, 1190afe10358SDmitry Torokhov "failed to enable vccio regulator: %d\n", 1191afe10358SDmitry Torokhov error); 1192afe10358SDmitry Torokhov regulator_disable(ts->vcc33); 1193afe10358SDmitry Torokhov goto release_reset_gpio; 1194afe10358SDmitry Torokhov } 1195afe10358SDmitry Torokhov 1196afe10358SDmitry Torokhov /* 1197afe10358SDmitry Torokhov * We need to wait a bit after powering on controller before 1198afe10358SDmitry Torokhov * we are allowed to release reset GPIO. 1199afe10358SDmitry Torokhov */ 1200afe10358SDmitry Torokhov udelay(ELAN_POWERON_DELAY_USEC); 1201afe10358SDmitry Torokhov 1202afe10358SDmitry Torokhov release_reset_gpio: 1203afe10358SDmitry Torokhov gpiod_set_value_cansleep(ts->reset_gpio, 0); 1204afe10358SDmitry Torokhov if (error) 1205afe10358SDmitry Torokhov return error; 1206afe10358SDmitry Torokhov 1207afe10358SDmitry Torokhov msleep(ELAN_RESET_DELAY_MSEC); 1208afe10358SDmitry Torokhov 1209afe10358SDmitry Torokhov return 0; 1210afe10358SDmitry Torokhov } 1211afe10358SDmitry Torokhov 1212afe10358SDmitry Torokhov static void elants_i2c_power_off(void *_data) 1213afe10358SDmitry Torokhov { 1214afe10358SDmitry Torokhov struct elants_data *ts = _data; 1215afe10358SDmitry Torokhov 1216afe10358SDmitry Torokhov if (!IS_ERR_OR_NULL(ts->reset_gpio)) { 1217afe10358SDmitry Torokhov /* 1218afe10358SDmitry Torokhov * Activate reset gpio to prevent leakage through the 1219afe10358SDmitry Torokhov * pin once we shut off power to the controller. 1220afe10358SDmitry Torokhov */ 1221afe10358SDmitry Torokhov gpiod_set_value_cansleep(ts->reset_gpio, 1); 1222afe10358SDmitry Torokhov regulator_disable(ts->vccio); 1223afe10358SDmitry Torokhov regulator_disable(ts->vcc33); 1224afe10358SDmitry Torokhov } 1225afe10358SDmitry Torokhov } 1226afe10358SDmitry Torokhov 122766aee900SScott Liu static int elants_i2c_probe(struct i2c_client *client, 122866aee900SScott Liu const struct i2c_device_id *id) 122966aee900SScott Liu { 123066aee900SScott Liu union i2c_smbus_data dummy; 123166aee900SScott Liu struct elants_data *ts; 123266aee900SScott Liu unsigned long irqflags; 123366aee900SScott Liu int error; 123466aee900SScott Liu 123566aee900SScott Liu if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 123666aee900SScott Liu dev_err(&client->dev, 123766aee900SScott Liu "%s: i2c check functionality error\n", DEVICE_NAME); 123866aee900SScott Liu return -ENXIO; 123966aee900SScott Liu } 124066aee900SScott Liu 124166aee900SScott Liu ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); 124266aee900SScott Liu if (!ts) 124366aee900SScott Liu return -ENOMEM; 124466aee900SScott Liu 124566aee900SScott Liu mutex_init(&ts->sysfs_mutex); 124666aee900SScott Liu init_completion(&ts->cmd_done); 124766aee900SScott Liu 124866aee900SScott Liu ts->client = client; 124966aee900SScott Liu i2c_set_clientdata(client, ts); 125066aee900SScott Liu 1251afe10358SDmitry Torokhov ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); 1252afe10358SDmitry Torokhov if (IS_ERR(ts->vcc33)) { 1253afe10358SDmitry Torokhov error = PTR_ERR(ts->vcc33); 1254afe10358SDmitry Torokhov if (error != -EPROBE_DEFER) 1255afe10358SDmitry Torokhov dev_err(&client->dev, 1256afe10358SDmitry Torokhov "Failed to get 'vcc33' regulator: %d\n", 1257afe10358SDmitry Torokhov error); 1258afe10358SDmitry Torokhov return error; 1259afe10358SDmitry Torokhov } 1260afe10358SDmitry Torokhov 1261afe10358SDmitry Torokhov ts->vccio = devm_regulator_get(&client->dev, "vccio"); 1262afe10358SDmitry Torokhov if (IS_ERR(ts->vccio)) { 1263afe10358SDmitry Torokhov error = PTR_ERR(ts->vccio); 1264afe10358SDmitry Torokhov if (error != -EPROBE_DEFER) 1265afe10358SDmitry Torokhov dev_err(&client->dev, 1266afe10358SDmitry Torokhov "Failed to get 'vccio' regulator: %d\n", 1267afe10358SDmitry Torokhov error); 1268afe10358SDmitry Torokhov return error; 1269afe10358SDmitry Torokhov } 1270afe10358SDmitry Torokhov 12717229b87bSStephen Rothwell ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); 1272afe10358SDmitry Torokhov if (IS_ERR(ts->reset_gpio)) { 1273afe10358SDmitry Torokhov error = PTR_ERR(ts->reset_gpio); 1274afe10358SDmitry Torokhov 1275afe10358SDmitry Torokhov if (error == -EPROBE_DEFER) 1276afe10358SDmitry Torokhov return error; 1277afe10358SDmitry Torokhov 1278afe10358SDmitry Torokhov if (error != -ENOENT && error != -ENOSYS) { 1279afe10358SDmitry Torokhov dev_err(&client->dev, 1280afe10358SDmitry Torokhov "failed to get reset gpio: %d\n", 1281afe10358SDmitry Torokhov error); 1282afe10358SDmitry Torokhov return error; 1283afe10358SDmitry Torokhov } 1284afe10358SDmitry Torokhov 1285afe10358SDmitry Torokhov ts->keep_power_in_suspend = true; 1286afe10358SDmitry Torokhov } 1287afe10358SDmitry Torokhov 1288afe10358SDmitry Torokhov error = elants_i2c_power_on(ts); 1289afe10358SDmitry Torokhov if (error) 1290afe10358SDmitry Torokhov return error; 1291afe10358SDmitry Torokhov 1292afe10358SDmitry Torokhov error = devm_add_action(&client->dev, elants_i2c_power_off, ts); 1293afe10358SDmitry Torokhov if (error) { 1294afe10358SDmitry Torokhov dev_err(&client->dev, 1295afe10358SDmitry Torokhov "failed to install power off action: %d\n", error); 1296afe10358SDmitry Torokhov elants_i2c_power_off(ts); 1297afe10358SDmitry Torokhov return error; 1298afe10358SDmitry Torokhov } 1299afe10358SDmitry Torokhov 1300afe10358SDmitry Torokhov /* Make sure there is something at this address */ 1301afe10358SDmitry Torokhov if (i2c_smbus_xfer(client->adapter, client->addr, 0, 1302afe10358SDmitry Torokhov I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { 1303afe10358SDmitry Torokhov dev_err(&client->dev, "nothing at this address\n"); 1304afe10358SDmitry Torokhov return -ENXIO; 1305afe10358SDmitry Torokhov } 1306afe10358SDmitry Torokhov 130766aee900SScott Liu error = elants_i2c_initialize(ts); 130866aee900SScott Liu if (error) { 130966aee900SScott Liu dev_err(&client->dev, "failed to initialize: %d\n", error); 131066aee900SScott Liu return error; 131166aee900SScott Liu } 131266aee900SScott Liu 131366aee900SScott Liu ts->input = devm_input_allocate_device(&client->dev); 131466aee900SScott Liu if (!ts->input) { 131566aee900SScott Liu dev_err(&client->dev, "Failed to allocate input device\n"); 131666aee900SScott Liu return -ENOMEM; 131766aee900SScott Liu } 131866aee900SScott Liu 131966aee900SScott Liu ts->input->name = "Elan Touchscreen"; 132066aee900SScott Liu ts->input->id.bustype = BUS_I2C; 132166aee900SScott Liu 132266aee900SScott Liu /* Multitouch input params setup */ 132366aee900SScott Liu 132466aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); 132566aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); 132666aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 132766aee900SScott Liu input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); 1328f27ad893SJohnny Chuang input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE, 1329f27ad893SJohnny Chuang 0, MT_TOOL_PALM, 0, 0); 133066aee900SScott Liu input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); 133166aee900SScott Liu input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); 13324238e52cSJohnny Chuang if (ts->major_res > 0) 13334238e52cSJohnny Chuang input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); 133466aee900SScott Liu 133568334dbaSMichał Mirosław touchscreen_parse_properties(ts->input, true, &ts->prop); 133668334dbaSMichał Mirosław 13376def17b1SMichał Mirosław error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, 13386def17b1SMichał Mirosław INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 13396def17b1SMichał Mirosław if (error) { 13406def17b1SMichał Mirosław dev_err(&client->dev, 13416def17b1SMichał Mirosław "failed to initialize MT slots: %d\n", error); 13426def17b1SMichał Mirosław return error; 13436def17b1SMichał Mirosław } 13446def17b1SMichał Mirosław 134566aee900SScott Liu error = input_register_device(ts->input); 134666aee900SScott Liu if (error) { 134766aee900SScott Liu dev_err(&client->dev, 134866aee900SScott Liu "unable to register input device: %d\n", error); 134966aee900SScott Liu return error; 135066aee900SScott Liu } 135166aee900SScott Liu 135266aee900SScott Liu /* 13534c83c071SDmitry Torokhov * Platform code (ACPI, DTS) should normally set up interrupt 13544c83c071SDmitry Torokhov * for us, but in case it did not let's fall back to using falling 13554c83c071SDmitry Torokhov * edge to be compatible with older Chromebooks. 135666aee900SScott Liu */ 13574c83c071SDmitry Torokhov irqflags = irq_get_trigger_type(client->irq); 13584c83c071SDmitry Torokhov if (!irqflags) 13594c83c071SDmitry Torokhov irqflags = IRQF_TRIGGER_FALLING; 136066aee900SScott Liu 136166aee900SScott Liu error = devm_request_threaded_irq(&client->dev, client->irq, 136266aee900SScott Liu NULL, elants_i2c_irq, 136366aee900SScott Liu irqflags | IRQF_ONESHOT, 136466aee900SScott Liu client->name, ts); 136566aee900SScott Liu if (error) { 136666aee900SScott Liu dev_err(&client->dev, "Failed to register interrupt\n"); 136766aee900SScott Liu return error; 136866aee900SScott Liu } 136966aee900SScott Liu 137066aee900SScott Liu /* 137166aee900SScott Liu * Systems using device tree should set up wakeup via DTS, 137266aee900SScott Liu * the rest will configure device as wakeup source by default. 137366aee900SScott Liu */ 137466aee900SScott Liu if (!client->dev.of_node) 137566aee900SScott Liu device_init_wakeup(&client->dev, true); 137666aee900SScott Liu 13778db69a9aSAndi Shyti error = devm_device_add_group(&client->dev, &elants_attribute_group); 137866aee900SScott Liu if (error) { 137966aee900SScott Liu dev_err(&client->dev, "failed to create sysfs attributes: %d\n", 138066aee900SScott Liu error); 138166aee900SScott Liu return error; 138266aee900SScott Liu } 138366aee900SScott Liu 138466aee900SScott Liu return 0; 138566aee900SScott Liu } 138666aee900SScott Liu 138766aee900SScott Liu static int __maybe_unused elants_i2c_suspend(struct device *dev) 138866aee900SScott Liu { 138966aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 139066aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 139166aee900SScott Liu const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; 139266aee900SScott Liu int retry_cnt; 139366aee900SScott Liu int error; 139466aee900SScott Liu 139566aee900SScott Liu /* Command not support in IAP recovery mode */ 139666aee900SScott Liu if (ts->iap_mode != ELAN_IAP_OPERATIONAL) 139766aee900SScott Liu return -EBUSY; 139866aee900SScott Liu 139966aee900SScott Liu disable_irq(client->irq); 140066aee900SScott Liu 1401478e5ed1SJames Chen if (device_may_wakeup(dev)) { 1402478e5ed1SJames Chen /* 1403478e5ed1SJames Chen * The device will automatically enter idle mode 1404478e5ed1SJames Chen * that has reduced power consumption. 1405478e5ed1SJames Chen */ 1406478e5ed1SJames Chen ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); 1407478e5ed1SJames Chen } else if (ts->keep_power_in_suspend) { 140866aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 140966aee900SScott Liu error = elants_i2c_send(client, set_sleep_cmd, 141066aee900SScott Liu sizeof(set_sleep_cmd)); 141166aee900SScott Liu if (!error) 141266aee900SScott Liu break; 141366aee900SScott Liu 1414afe10358SDmitry Torokhov dev_err(&client->dev, 1415afe10358SDmitry Torokhov "suspend command failed: %d\n", error); 141666aee900SScott Liu } 1417afe10358SDmitry Torokhov } else { 1418afe10358SDmitry Torokhov elants_i2c_power_off(ts); 1419afe10358SDmitry Torokhov } 142066aee900SScott Liu 142166aee900SScott Liu return 0; 142266aee900SScott Liu } 142366aee900SScott Liu 142466aee900SScott Liu static int __maybe_unused elants_i2c_resume(struct device *dev) 142566aee900SScott Liu { 142666aee900SScott Liu struct i2c_client *client = to_i2c_client(dev); 142766aee900SScott Liu struct elants_data *ts = i2c_get_clientdata(client); 142866aee900SScott Liu const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; 142966aee900SScott Liu int retry_cnt; 143066aee900SScott Liu int error; 143166aee900SScott Liu 1432478e5ed1SJames Chen if (device_may_wakeup(dev)) { 1433478e5ed1SJames Chen if (ts->wake_irq_enabled) 143466aee900SScott Liu disable_irq_wake(client->irq); 1435478e5ed1SJames Chen elants_i2c_sw_reset(client); 1436478e5ed1SJames Chen } else if (ts->keep_power_in_suspend) { 143766aee900SScott Liu for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { 143866aee900SScott Liu error = elants_i2c_send(client, set_active_cmd, 143966aee900SScott Liu sizeof(set_active_cmd)); 144066aee900SScott Liu if (!error) 144166aee900SScott Liu break; 144266aee900SScott Liu 1443afe10358SDmitry Torokhov dev_err(&client->dev, 1444afe10358SDmitry Torokhov "resume command failed: %d\n", error); 1445afe10358SDmitry Torokhov } 1446afe10358SDmitry Torokhov } else { 1447afe10358SDmitry Torokhov elants_i2c_power_on(ts); 1448afe10358SDmitry Torokhov elants_i2c_initialize(ts); 144966aee900SScott Liu } 145066aee900SScott Liu 145166aee900SScott Liu ts->state = ELAN_STATE_NORMAL; 145266aee900SScott Liu enable_irq(client->irq); 145366aee900SScott Liu 145466aee900SScott Liu return 0; 145566aee900SScott Liu } 145666aee900SScott Liu 145766aee900SScott Liu static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, 145866aee900SScott Liu elants_i2c_suspend, elants_i2c_resume); 145966aee900SScott Liu 146066aee900SScott Liu static const struct i2c_device_id elants_i2c_id[] = { 146166aee900SScott Liu { DEVICE_NAME, 0 }, 146266aee900SScott Liu { } 146366aee900SScott Liu }; 146466aee900SScott Liu MODULE_DEVICE_TABLE(i2c, elants_i2c_id); 146566aee900SScott Liu 146666aee900SScott Liu #ifdef CONFIG_ACPI 146766aee900SScott Liu static const struct acpi_device_id elants_acpi_id[] = { 146866aee900SScott Liu { "ELAN0001", 0 }, 146966aee900SScott Liu { } 147066aee900SScott Liu }; 147166aee900SScott Liu MODULE_DEVICE_TABLE(acpi, elants_acpi_id); 147266aee900SScott Liu #endif 147366aee900SScott Liu 147466aee900SScott Liu #ifdef CONFIG_OF 147566aee900SScott Liu static const struct of_device_id elants_of_match[] = { 147666aee900SScott Liu { .compatible = "elan,ekth3500" }, 147766aee900SScott Liu { /* sentinel */ } 147866aee900SScott Liu }; 147966aee900SScott Liu MODULE_DEVICE_TABLE(of, elants_of_match); 148066aee900SScott Liu #endif 148166aee900SScott Liu 148266aee900SScott Liu static struct i2c_driver elants_i2c_driver = { 148366aee900SScott Liu .probe = elants_i2c_probe, 148466aee900SScott Liu .id_table = elants_i2c_id, 148566aee900SScott Liu .driver = { 148666aee900SScott Liu .name = DEVICE_NAME, 148766aee900SScott Liu .pm = &elants_i2c_pm_ops, 148866aee900SScott Liu .acpi_match_table = ACPI_PTR(elants_acpi_id), 148966aee900SScott Liu .of_match_table = of_match_ptr(elants_of_match), 14909f6a07b6SDmitry Torokhov .probe_type = PROBE_PREFER_ASYNCHRONOUS, 149166aee900SScott Liu }, 149266aee900SScott Liu }; 149366aee900SScott Liu module_i2c_driver(elants_i2c_driver); 149466aee900SScott Liu 149566aee900SScott Liu MODULE_AUTHOR("Scott Liu <scott.liu@emc.com.tw>"); 149666aee900SScott Liu MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); 149766aee900SScott Liu MODULE_LICENSE("GPL"); 1498