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