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>
392e758f53SRaul 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 
118c3991107SDouglas Anderson #define ELAN_POWERON_DELAY_USEC	5000
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 
elants_i2c_send(struct i2c_client * client,const void * data,size_t size)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 
elants_i2c_read(struct i2c_client * client,void * data,size_t size)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 
elants_i2c_execute_command(struct i2c_client * client,const u8 * cmd,size_t cmd_size,u8 * resp,size_t resp_size,int retries,const char * cmd_name)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 
elants_i2c_calibrate(struct elants_data * ts)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 
elants_i2c_sw_reset(struct i2c_client * client)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 
elants_i2c_parse_version(u8 * buf)36066aee900SScott Liu static u16 elants_i2c_parse_version(u8 *buf)
36166aee900SScott Liu {
36266aee900SScott Liu 	return get_unaligned_be32(buf) >> 4;
36366aee900SScott Liu }
36466aee900SScott Liu 
elants_i2c_query_hw_version(struct elants_data * ts)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 
elants_i2c_query_fw_version(struct elants_data * ts)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 
elants_i2c_query_test_version(struct elants_data * ts)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 
elants_i2c_query_bc_version(struct elants_data * ts)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 
elants_i2c_query_ts_info_ektf(struct elants_data * ts)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 
elants_i2c_query_ts_info_ekth(struct elants_data * ts)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 
elants_i2c_fastboot(struct i2c_client * client)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 
elants_i2c_initialize(struct elants_data * ts)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 
elants_i2c_fw_write_page(struct i2c_client * client,const void * page)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 
elants_i2c_validate_remark_id(struct elants_data * ts,const struct firmware * fw)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 
elants_i2c_should_check_remark_id(struct elants_data * ts)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 
elants_i2c_do_update_firmware(struct i2c_client * client,const struct firmware * fw,bool force)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 
elants_i2c_fw_update(struct elants_data * ts)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 
elants_i2c_mt_event(struct elants_data * ts,u8 * buf,size_t packet_size)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 
elants_i2c_calculate_checksum(u8 * buf)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 
elants_i2c_event(struct elants_data * ts,u8 * buf,size_t packet_size)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 
elants_i2c_irq(int irq,void * _dev)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  */
calibrate_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
write_update_fw(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
show_iap_mode(struct device * dev,struct device_attribute * attr,char * buf)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 
show_calibration_count(struct device * dev,struct device_attribute * attr,char * buf)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 
elants_version_attribute_show(struct device * dev,struct device_attribute * dattr,char * buf)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 
elants_i2c_power_on(struct elants_data * ts)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 	 */
1353c3991107SDouglas Anderson 	usleep_range(ELAN_POWERON_DELAY_USEC, ELAN_POWERON_DELAY_USEC + 100);
1354afe10358SDmitry Torokhov 
1355afe10358SDmitry Torokhov 	gpiod_set_value_cansleep(ts->reset_gpio, 0);
1356afe10358SDmitry Torokhov 
1357afe10358SDmitry Torokhov 	msleep(ELAN_RESET_DELAY_MSEC);
1358afe10358SDmitry Torokhov 
1359afe10358SDmitry Torokhov 	return 0;
1360afe10358SDmitry Torokhov }
1361afe10358SDmitry Torokhov 
elants_i2c_power_off(void * _data)1362afe10358SDmitry Torokhov static void elants_i2c_power_off(void *_data)
1363afe10358SDmitry Torokhov {
1364afe10358SDmitry Torokhov 	struct elants_data *ts = _data;
1365afe10358SDmitry Torokhov 
1366afe10358SDmitry Torokhov 	if (!IS_ERR_OR_NULL(ts->reset_gpio)) {
1367afe10358SDmitry Torokhov 		/*
1368afe10358SDmitry Torokhov 		 * Activate reset gpio to prevent leakage through the
1369afe10358SDmitry Torokhov 		 * pin once we shut off power to the controller.
1370afe10358SDmitry Torokhov 		 */
1371afe10358SDmitry Torokhov 		gpiod_set_value_cansleep(ts->reset_gpio, 1);
1372afe10358SDmitry Torokhov 		regulator_disable(ts->vccio);
1373afe10358SDmitry Torokhov 		regulator_disable(ts->vcc33);
1374afe10358SDmitry Torokhov 	}
1375afe10358SDmitry Torokhov }
1376afe10358SDmitry Torokhov 
137765299e8bSHans de Goede #ifdef CONFIG_ACPI
137865299e8bSHans de Goede static const struct acpi_device_id i2c_hid_ids[] = {
137965299e8bSHans de Goede 	{"ACPI0C50", 0 },
138065299e8bSHans de Goede 	{"PNP0C50", 0 },
138165299e8bSHans de Goede 	{ },
138265299e8bSHans de Goede };
138365299e8bSHans de Goede 
138465299e8bSHans de Goede static const guid_t i2c_hid_guid =
138565299e8bSHans de Goede 	GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
138665299e8bSHans de Goede 		  0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
138765299e8bSHans de Goede 
elants_acpi_is_hid_device(struct device * dev)138865299e8bSHans de Goede static bool elants_acpi_is_hid_device(struct device *dev)
138965299e8bSHans de Goede {
139065299e8bSHans de Goede 	acpi_handle handle = ACPI_HANDLE(dev);
139165299e8bSHans de Goede 	union acpi_object *obj;
139265299e8bSHans de Goede 
139365299e8bSHans de Goede 	if (acpi_match_device_ids(ACPI_COMPANION(dev), i2c_hid_ids))
139465299e8bSHans de Goede 		return false;
139565299e8bSHans de Goede 
139665299e8bSHans de Goede 	obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, ACPI_TYPE_INTEGER);
139765299e8bSHans de Goede 	if (obj) {
139865299e8bSHans de Goede 		ACPI_FREE(obj);
139965299e8bSHans de Goede 		return true;
140065299e8bSHans de Goede 	}
140165299e8bSHans de Goede 
140265299e8bSHans de Goede 	return false;
140365299e8bSHans de Goede }
140465299e8bSHans de Goede #else
elants_acpi_is_hid_device(struct device * dev)140565299e8bSHans de Goede static bool elants_acpi_is_hid_device(struct device *dev)
140665299e8bSHans de Goede {
140765299e8bSHans de Goede 	return false;
140865299e8bSHans de Goede }
140965299e8bSHans de Goede #endif
141065299e8bSHans de Goede 
elants_i2c_probe(struct i2c_client * client)141145a4b683STakashi Iwai static int elants_i2c_probe(struct i2c_client *client)
141266aee900SScott Liu {
141366aee900SScott Liu 	union i2c_smbus_data dummy;
141466aee900SScott Liu 	struct elants_data *ts;
141566aee900SScott Liu 	unsigned long irqflags;
141666aee900SScott Liu 	int error;
141766aee900SScott Liu 
141865299e8bSHans de Goede 	/* Don't bind to i2c-hid compatible devices, these are handled by the i2c-hid drv. */
141965299e8bSHans de Goede 	if (elants_acpi_is_hid_device(&client->dev)) {
142065299e8bSHans de Goede 		dev_warn(&client->dev, "This device appears to be an I2C-HID device, not binding\n");
142165299e8bSHans de Goede 		return -ENODEV;
142265299e8bSHans de Goede 	}
142365299e8bSHans de Goede 
142466aee900SScott Liu 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
142565299e8bSHans de Goede 		dev_err(&client->dev, "I2C check functionality error\n");
142666aee900SScott Liu 		return -ENXIO;
142766aee900SScott Liu 	}
142866aee900SScott Liu 
142966aee900SScott Liu 	ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL);
143066aee900SScott Liu 	if (!ts)
143166aee900SScott Liu 		return -ENOMEM;
143266aee900SScott Liu 
143366aee900SScott Liu 	mutex_init(&ts->sysfs_mutex);
143466aee900SScott Liu 	init_completion(&ts->cmd_done);
143566aee900SScott Liu 
143666aee900SScott Liu 	ts->client = client;
1437b9c0ebb8STakashi Iwai 	ts->chip_id = (enum elants_chip_id)(uintptr_t)device_get_match_data(&client->dev);
143866aee900SScott Liu 	i2c_set_clientdata(client, ts);
143966aee900SScott Liu 
1440afe10358SDmitry Torokhov 	ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
1441*e89f0de5SKrzysztof Kozlowski 	if (IS_ERR(ts->vcc33))
1442*e89f0de5SKrzysztof Kozlowski 		return dev_err_probe(&client->dev, PTR_ERR(ts->vcc33),
1443*e89f0de5SKrzysztof Kozlowski 				     "Failed to get 'vcc33' regulator\n");
1444afe10358SDmitry Torokhov 
1445afe10358SDmitry Torokhov 	ts->vccio = devm_regulator_get(&client->dev, "vccio");
1446*e89f0de5SKrzysztof Kozlowski 	if (IS_ERR(ts->vccio))
1447*e89f0de5SKrzysztof Kozlowski 		return dev_err_probe(&client->dev, PTR_ERR(ts->vccio),
1448*e89f0de5SKrzysztof Kozlowski 				     "Failed to get 'vccio' regulator\n");
1449afe10358SDmitry Torokhov 
1450a85fbd64SDouglas Anderson 	ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
1451afe10358SDmitry Torokhov 	if (IS_ERR(ts->reset_gpio)) {
1452afe10358SDmitry Torokhov 		error = PTR_ERR(ts->reset_gpio);
1453afe10358SDmitry Torokhov 
1454afe10358SDmitry Torokhov 		if (error == -EPROBE_DEFER)
1455afe10358SDmitry Torokhov 			return error;
1456afe10358SDmitry Torokhov 
1457afe10358SDmitry Torokhov 		if (error != -ENOENT && error != -ENOSYS) {
1458afe10358SDmitry Torokhov 			dev_err(&client->dev,
1459afe10358SDmitry Torokhov 				"failed to get reset gpio: %d\n",
1460afe10358SDmitry Torokhov 				error);
1461afe10358SDmitry Torokhov 			return error;
1462afe10358SDmitry Torokhov 		}
1463afe10358SDmitry Torokhov 
1464afe10358SDmitry Torokhov 		ts->keep_power_in_suspend = true;
1465afe10358SDmitry Torokhov 	}
1466afe10358SDmitry Torokhov 
1467afe10358SDmitry Torokhov 	error = elants_i2c_power_on(ts);
1468afe10358SDmitry Torokhov 	if (error)
1469afe10358SDmitry Torokhov 		return error;
1470afe10358SDmitry Torokhov 
1471b083704fSCai Huoqing 	error = devm_add_action_or_reset(&client->dev,
1472b083704fSCai Huoqing 					 elants_i2c_power_off, ts);
1473afe10358SDmitry Torokhov 	if (error) {
1474afe10358SDmitry Torokhov 		dev_err(&client->dev,
1475afe10358SDmitry Torokhov 			"failed to install power off action: %d\n", error);
1476afe10358SDmitry Torokhov 		return error;
1477afe10358SDmitry Torokhov 	}
1478afe10358SDmitry Torokhov 
1479afe10358SDmitry Torokhov 	/* Make sure there is something at this address */
1480afe10358SDmitry Torokhov 	if (i2c_smbus_xfer(client->adapter, client->addr, 0,
1481afe10358SDmitry Torokhov 			   I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) {
1482afe10358SDmitry Torokhov 		dev_err(&client->dev, "nothing at this address\n");
1483afe10358SDmitry Torokhov 		return -ENXIO;
1484afe10358SDmitry Torokhov 	}
1485afe10358SDmitry Torokhov 
148666aee900SScott Liu 	error = elants_i2c_initialize(ts);
148766aee900SScott Liu 	if (error) {
148866aee900SScott Liu 		dev_err(&client->dev, "failed to initialize: %d\n", error);
148966aee900SScott Liu 		return error;
149066aee900SScott Liu 	}
149166aee900SScott Liu 
149266aee900SScott Liu 	ts->input = devm_input_allocate_device(&client->dev);
149366aee900SScott Liu 	if (!ts->input) {
149466aee900SScott Liu 		dev_err(&client->dev, "Failed to allocate input device\n");
149566aee900SScott Liu 		return -ENOMEM;
149666aee900SScott Liu 	}
149766aee900SScott Liu 
149866aee900SScott Liu 	ts->input->name = "Elan Touchscreen";
149966aee900SScott Liu 	ts->input->id.bustype = BUS_I2C;
150066aee900SScott Liu 
150166aee900SScott Liu 	/* Multitouch input params setup */
150266aee900SScott Liu 
150366aee900SScott Liu 	input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0);
150466aee900SScott Liu 	input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0);
150566aee900SScott Liu 	input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
150666aee900SScott Liu 	input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
1507f27ad893SJohnny Chuang 	input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE,
1508f27ad893SJohnny Chuang 			     0, MT_TOOL_PALM, 0, 0);
15099517b95bSMichał Mirosław 
15109517b95bSMichał Mirosław 	touchscreen_parse_properties(ts->input, true, &ts->prop);
15119517b95bSMichał Mirosław 
1512781bab32SDmitry Osipenko 	if (ts->chip_id == EKTF3624 && ts->phy_x && ts->phy_y) {
15139517b95bSMichał Mirosław 		/* calculate resolution from size */
15149517b95bSMichał Mirosław 		ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x);
15159517b95bSMichał Mirosław 		ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y);
15169517b95bSMichał Mirosław 	}
15179517b95bSMichał Mirosław 
151866aee900SScott Liu 	input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
151966aee900SScott Liu 	input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
15204238e52cSJohnny Chuang 	input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res);
152166aee900SScott Liu 
15226def17b1SMichał Mirosław 	error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
15236def17b1SMichał Mirosław 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
15246def17b1SMichał Mirosław 	if (error) {
15256def17b1SMichał Mirosław 		dev_err(&client->dev,
15266def17b1SMichał Mirosław 			"failed to initialize MT slots: %d\n", error);
15276def17b1SMichał Mirosław 		return error;
15286def17b1SMichał Mirosław 	}
15296def17b1SMichał Mirosław 
153066aee900SScott Liu 	error = input_register_device(ts->input);
153166aee900SScott Liu 	if (error) {
153266aee900SScott Liu 		dev_err(&client->dev,
153366aee900SScott Liu 			"unable to register input device: %d\n", error);
153466aee900SScott Liu 		return error;
153566aee900SScott Liu 	}
153666aee900SScott Liu 
153766aee900SScott Liu 	/*
15384c83c071SDmitry Torokhov 	 * Platform code (ACPI, DTS) should normally set up interrupt
15394c83c071SDmitry Torokhov 	 * for us, but in case it did not let's fall back to using falling
15404c83c071SDmitry Torokhov 	 * edge to be compatible with older Chromebooks.
154166aee900SScott Liu 	 */
15424c83c071SDmitry Torokhov 	irqflags = irq_get_trigger_type(client->irq);
15434c83c071SDmitry Torokhov 	if (!irqflags)
15444c83c071SDmitry Torokhov 		irqflags = IRQF_TRIGGER_FALLING;
154566aee900SScott Liu 
154666aee900SScott Liu 	error = devm_request_threaded_irq(&client->dev, client->irq,
154766aee900SScott Liu 					  NULL, elants_i2c_irq,
154866aee900SScott Liu 					  irqflags | IRQF_ONESHOT,
154966aee900SScott Liu 					  client->name, ts);
155066aee900SScott Liu 	if (error) {
155166aee900SScott Liu 		dev_err(&client->dev, "Failed to register interrupt\n");
155266aee900SScott Liu 		return error;
155366aee900SScott Liu 	}
155466aee900SScott Liu 
15558db69a9aSAndi Shyti 	error = devm_device_add_group(&client->dev, &elants_attribute_group);
155666aee900SScott Liu 	if (error) {
155766aee900SScott Liu 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
155866aee900SScott Liu 			error);
155966aee900SScott Liu 		return error;
156066aee900SScott Liu 	}
156166aee900SScott Liu 
156266aee900SScott Liu 	return 0;
156366aee900SScott Liu }
156466aee900SScott Liu 
elants_i2c_suspend(struct device * dev)1565df0f6734SJonathan Cameron static int elants_i2c_suspend(struct device *dev)
156666aee900SScott Liu {
156766aee900SScott Liu 	struct i2c_client *client = to_i2c_client(dev);
156866aee900SScott Liu 	struct elants_data *ts = i2c_get_clientdata(client);
1569c18b443cSMichał Mirosław 	const u8 set_sleep_cmd[] = {
1570c18b443cSMichał Mirosław 		CMD_HEADER_WRITE, E_POWER_STATE_SLEEP, 0x00, 0x01
1571c18b443cSMichał Mirosław 	};
157266aee900SScott Liu 	int retry_cnt;
157366aee900SScott Liu 	int error;
157466aee900SScott Liu 
157566aee900SScott Liu 	/* Command not support in IAP recovery mode */
157666aee900SScott Liu 	if (ts->iap_mode != ELAN_IAP_OPERATIONAL)
157766aee900SScott Liu 		return -EBUSY;
157866aee900SScott Liu 
157966aee900SScott Liu 	disable_irq(client->irq);
158066aee900SScott Liu 
1581478e5ed1SJames Chen 	if (device_may_wakeup(dev)) {
1582478e5ed1SJames Chen 		/*
1583478e5ed1SJames Chen 		 * The device will automatically enter idle mode
1584478e5ed1SJames Chen 		 * that has reduced power consumption.
1585478e5ed1SJames Chen 		 */
15862e758f53SRaul E Rangel 		return 0;
1587478e5ed1SJames Chen 	} else if (ts->keep_power_in_suspend) {
158866aee900SScott Liu 		for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
158966aee900SScott Liu 			error = elants_i2c_send(client, set_sleep_cmd,
159066aee900SScott Liu 						sizeof(set_sleep_cmd));
159166aee900SScott Liu 			if (!error)
159266aee900SScott Liu 				break;
159366aee900SScott Liu 
1594afe10358SDmitry Torokhov 			dev_err(&client->dev,
1595afe10358SDmitry Torokhov 				"suspend command failed: %d\n", error);
159666aee900SScott Liu 		}
1597afe10358SDmitry Torokhov 	} else {
1598afe10358SDmitry Torokhov 		elants_i2c_power_off(ts);
1599afe10358SDmitry Torokhov 	}
160066aee900SScott Liu 
160166aee900SScott Liu 	return 0;
160266aee900SScott Liu }
160366aee900SScott Liu 
elants_i2c_resume(struct device * dev)1604df0f6734SJonathan Cameron static int elants_i2c_resume(struct device *dev)
160566aee900SScott Liu {
160666aee900SScott Liu 	struct i2c_client *client = to_i2c_client(dev);
160766aee900SScott Liu 	struct elants_data *ts = i2c_get_clientdata(client);
1608c18b443cSMichał Mirosław 	const u8 set_active_cmd[] = {
1609c18b443cSMichał Mirosław 		CMD_HEADER_WRITE, E_POWER_STATE_RESUME, 0x00, 0x01
1610c18b443cSMichał Mirosław 	};
161166aee900SScott Liu 	int retry_cnt;
161266aee900SScott Liu 	int error;
161366aee900SScott Liu 
1614478e5ed1SJames Chen 	if (device_may_wakeup(dev)) {
1615478e5ed1SJames Chen 		elants_i2c_sw_reset(client);
1616478e5ed1SJames Chen 	} else if (ts->keep_power_in_suspend) {
161766aee900SScott Liu 		for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
161866aee900SScott Liu 			error = elants_i2c_send(client, set_active_cmd,
161966aee900SScott Liu 						sizeof(set_active_cmd));
162066aee900SScott Liu 			if (!error)
162166aee900SScott Liu 				break;
162266aee900SScott Liu 
1623afe10358SDmitry Torokhov 			dev_err(&client->dev,
1624afe10358SDmitry Torokhov 				"resume command failed: %d\n", error);
1625afe10358SDmitry Torokhov 		}
1626afe10358SDmitry Torokhov 	} else {
1627afe10358SDmitry Torokhov 		elants_i2c_power_on(ts);
1628afe10358SDmitry Torokhov 		elants_i2c_initialize(ts);
162966aee900SScott Liu 	}
163066aee900SScott Liu 
163166aee900SScott Liu 	ts->state = ELAN_STATE_NORMAL;
163266aee900SScott Liu 	enable_irq(client->irq);
163366aee900SScott Liu 
163466aee900SScott Liu 	return 0;
163566aee900SScott Liu }
163666aee900SScott Liu 
1637df0f6734SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
163866aee900SScott Liu 				elants_i2c_suspend, elants_i2c_resume);
163966aee900SScott Liu 
164066aee900SScott Liu static const struct i2c_device_id elants_i2c_id[] = {
16419517b95bSMichał Mirosław 	{ DEVICE_NAME, EKTH3500 },
16429517b95bSMichał Mirosław 	{ "ekth3500", EKTH3500 },
16439517b95bSMichał Mirosław 	{ "ektf3624", EKTF3624 },
164466aee900SScott Liu 	{ }
164566aee900SScott Liu };
164666aee900SScott Liu MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
164766aee900SScott Liu 
164866aee900SScott Liu #ifdef CONFIG_ACPI
164966aee900SScott Liu static const struct acpi_device_id elants_acpi_id[] = {
16509517b95bSMichał Mirosław 	{ "ELAN0001", EKTH3500 },
165166aee900SScott Liu 	{ }
165266aee900SScott Liu };
165366aee900SScott Liu MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
165466aee900SScott Liu #endif
165566aee900SScott Liu 
165666aee900SScott Liu #ifdef CONFIG_OF
165766aee900SScott Liu static const struct of_device_id elants_of_match[] = {
1658b9c0ebb8STakashi Iwai 	{ .compatible = "elan,ekth3500", .data = (void *)EKTH3500 },
1659b9c0ebb8STakashi Iwai 	{ .compatible = "elan,ektf3624", .data = (void *)EKTF3624 },
166066aee900SScott Liu 	{ /* sentinel */ }
166166aee900SScott Liu };
166266aee900SScott Liu MODULE_DEVICE_TABLE(of, elants_of_match);
166366aee900SScott Liu #endif
166466aee900SScott Liu 
166566aee900SScott Liu static struct i2c_driver elants_i2c_driver = {
1666d8bde56dSUwe Kleine-König 	.probe = elants_i2c_probe,
166766aee900SScott Liu 	.id_table = elants_i2c_id,
166866aee900SScott Liu 	.driver = {
166966aee900SScott Liu 		.name = DEVICE_NAME,
1670df0f6734SJonathan Cameron 		.pm = pm_sleep_ptr(&elants_i2c_pm_ops),
167166aee900SScott Liu 		.acpi_match_table = ACPI_PTR(elants_acpi_id),
167266aee900SScott Liu 		.of_match_table = of_match_ptr(elants_of_match),
16739f6a07b6SDmitry Torokhov 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
167466aee900SScott Liu 	},
167566aee900SScott Liu };
167666aee900SScott Liu module_i2c_driver(elants_i2c_driver);
167766aee900SScott Liu 
167866aee900SScott Liu MODULE_AUTHOR("Scott Liu <scott.liu@emc.com.tw>");
167966aee900SScott Liu MODULE_DESCRIPTION("Elan I2c Touchscreen driver");
168066aee900SScott Liu MODULE_LICENSE("GPL");
1681