xref: /openbmc/linux/drivers/input/touchscreen/raydium_i2c_ts.c (revision 48a2b783483b3ed9565348736a5148a11cfffad6)
1*48a2b783SJeffrey Lin /*
2*48a2b783SJeffrey Lin  * Raydium touchscreen I2C driver.
3*48a2b783SJeffrey Lin  *
4*48a2b783SJeffrey Lin  * Copyright (C) 2012-2014, Raydium Semiconductor Corporation.
5*48a2b783SJeffrey Lin  *
6*48a2b783SJeffrey Lin  * This program is free software; you can redistribute it and/or
7*48a2b783SJeffrey Lin  * modify it under the terms of the GNU General Public License
8*48a2b783SJeffrey Lin  * version 2, and only version 2, as published by the
9*48a2b783SJeffrey Lin  * Free Software Foundation.
10*48a2b783SJeffrey Lin  *
11*48a2b783SJeffrey Lin  * This program is distributed in the hope that it will be useful,
12*48a2b783SJeffrey Lin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*48a2b783SJeffrey Lin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*48a2b783SJeffrey Lin  * GNU General Public License for more details.
15*48a2b783SJeffrey Lin  *
16*48a2b783SJeffrey Lin  * Raydium reserves the right to make changes without further notice
17*48a2b783SJeffrey Lin  * to the materials described herein. Raydium does not assume any
18*48a2b783SJeffrey Lin  * liability arising out of the application described herein.
19*48a2b783SJeffrey Lin  *
20*48a2b783SJeffrey Lin  * Contact Raydium Semiconductor Corporation at www.rad-ic.com
21*48a2b783SJeffrey Lin  */
22*48a2b783SJeffrey Lin 
23*48a2b783SJeffrey Lin #include <linux/acpi.h>
24*48a2b783SJeffrey Lin #include <linux/delay.h>
25*48a2b783SJeffrey Lin #include <linux/firmware.h>
26*48a2b783SJeffrey Lin #include <linux/gpio/consumer.h>
27*48a2b783SJeffrey Lin #include <linux/i2c.h>
28*48a2b783SJeffrey Lin #include <linux/input.h>
29*48a2b783SJeffrey Lin #include <linux/input/mt.h>
30*48a2b783SJeffrey Lin #include <linux/interrupt.h>
31*48a2b783SJeffrey Lin #include <linux/module.h>
32*48a2b783SJeffrey Lin #include <linux/of.h>
33*48a2b783SJeffrey Lin #include <linux/regulator/consumer.h>
34*48a2b783SJeffrey Lin #include <linux/slab.h>
35*48a2b783SJeffrey Lin #include <asm/unaligned.h>
36*48a2b783SJeffrey Lin 
37*48a2b783SJeffrey Lin /* Slave I2C mode */
38*48a2b783SJeffrey Lin #define RM_BOOT_BLDR		0x02
39*48a2b783SJeffrey Lin #define RM_BOOT_MAIN		0x03
40*48a2b783SJeffrey Lin 
41*48a2b783SJeffrey Lin /* I2C bootoloader commands */
42*48a2b783SJeffrey Lin #define RM_CMD_BOOT_PAGE_WRT	0x0B		/* send bl page write */
43*48a2b783SJeffrey Lin #define RM_CMD_BOOT_WRT		0x11		/* send bl write */
44*48a2b783SJeffrey Lin #define RM_CMD_BOOT_ACK		0x22		/* send ack*/
45*48a2b783SJeffrey Lin #define RM_CMD_BOOT_CHK		0x33		/* send data check */
46*48a2b783SJeffrey Lin #define RM_CMD_BOOT_READ	0x44		/* send wait bl data ready*/
47*48a2b783SJeffrey Lin 
48*48a2b783SJeffrey Lin #define RM_BOOT_RDY		0xFF		/* bl data ready */
49*48a2b783SJeffrey Lin 
50*48a2b783SJeffrey Lin /* I2C main commands */
51*48a2b783SJeffrey Lin #define RM_CMD_QUERY_BANK	0x2B
52*48a2b783SJeffrey Lin #define RM_CMD_DATA_BANK	0x4D
53*48a2b783SJeffrey Lin #define RM_CMD_ENTER_SLEEP	0x4E
54*48a2b783SJeffrey Lin #define RM_CMD_BANK_SWITCH	0xAA
55*48a2b783SJeffrey Lin 
56*48a2b783SJeffrey Lin #define RM_RESET_MSG_ADDR	0x40000004
57*48a2b783SJeffrey Lin 
58*48a2b783SJeffrey Lin #define RM_MAX_READ_SIZE	56
59*48a2b783SJeffrey Lin 
60*48a2b783SJeffrey Lin /* Touch relative info */
61*48a2b783SJeffrey Lin #define RM_MAX_RETRIES		3
62*48a2b783SJeffrey Lin #define RM_MAX_TOUCH_NUM	10
63*48a2b783SJeffrey Lin #define RM_BOOT_DELAY_MS	100
64*48a2b783SJeffrey Lin 
65*48a2b783SJeffrey Lin /* Offsets in contact data */
66*48a2b783SJeffrey Lin #define RM_CONTACT_STATE_POS	0
67*48a2b783SJeffrey Lin #define RM_CONTACT_X_POS	1
68*48a2b783SJeffrey Lin #define RM_CONTACT_Y_POS	3
69*48a2b783SJeffrey Lin #define RM_CONTACT_PRESSURE_POS	5
70*48a2b783SJeffrey Lin #define RM_CONTACT_WIDTH_X_POS	6
71*48a2b783SJeffrey Lin #define RM_CONTACT_WIDTH_Y_POS	7
72*48a2b783SJeffrey Lin 
73*48a2b783SJeffrey Lin /* Bootloader relative info */
74*48a2b783SJeffrey Lin #define RM_BL_WRT_CMD_SIZE	3	/* bl flash wrt cmd size */
75*48a2b783SJeffrey Lin #define RM_BL_WRT_PKG_SIZE	32	/* bl wrt pkg size */
76*48a2b783SJeffrey Lin #define RM_BL_WRT_LEN		(RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE)
77*48a2b783SJeffrey Lin #define RM_FW_PAGE_SIZE		128
78*48a2b783SJeffrey Lin #define RM_MAX_FW_RETRIES	30
79*48a2b783SJeffrey Lin #define RM_MAX_FW_SIZE		0xD000
80*48a2b783SJeffrey Lin 
81*48a2b783SJeffrey Lin #define RM_POWERON_DELAY_USEC	500
82*48a2b783SJeffrey Lin #define RM_RESET_DELAY_MSEC	50
83*48a2b783SJeffrey Lin 
84*48a2b783SJeffrey Lin enum raydium_bl_cmd {
85*48a2b783SJeffrey Lin 	BL_HEADER = 0,
86*48a2b783SJeffrey Lin 	BL_PAGE_STR,
87*48a2b783SJeffrey Lin 	BL_PKG_IDX,
88*48a2b783SJeffrey Lin 	BL_DATA_STR,
89*48a2b783SJeffrey Lin };
90*48a2b783SJeffrey Lin 
91*48a2b783SJeffrey Lin enum raydium_bl_ack {
92*48a2b783SJeffrey Lin 	RAYDIUM_ACK_NULL = 0,
93*48a2b783SJeffrey Lin 	RAYDIUM_WAIT_READY,
94*48a2b783SJeffrey Lin 	RAYDIUM_PATH_READY,
95*48a2b783SJeffrey Lin };
96*48a2b783SJeffrey Lin 
97*48a2b783SJeffrey Lin enum raydium_boot_mode {
98*48a2b783SJeffrey Lin 	RAYDIUM_TS_MAIN = 0,
99*48a2b783SJeffrey Lin 	RAYDIUM_TS_BLDR,
100*48a2b783SJeffrey Lin };
101*48a2b783SJeffrey Lin 
102*48a2b783SJeffrey Lin /* Response to RM_CMD_DATA_BANK request */
103*48a2b783SJeffrey Lin struct raydium_data_info {
104*48a2b783SJeffrey Lin 	__le32 data_bank_addr;
105*48a2b783SJeffrey Lin 	u8 pkg_size;
106*48a2b783SJeffrey Lin 	u8 tp_info_size;
107*48a2b783SJeffrey Lin };
108*48a2b783SJeffrey Lin 
109*48a2b783SJeffrey Lin struct raydium_info {
110*48a2b783SJeffrey Lin 	__le32 hw_ver;		/*device version */
111*48a2b783SJeffrey Lin 	u8 main_ver;
112*48a2b783SJeffrey Lin 	u8 sub_ver;
113*48a2b783SJeffrey Lin 	__le16 ft_ver;		/* test version */
114*48a2b783SJeffrey Lin 	u8 x_num;
115*48a2b783SJeffrey Lin 	u8 y_num;
116*48a2b783SJeffrey Lin 	__le16 x_max;
117*48a2b783SJeffrey Lin 	__le16 y_max;
118*48a2b783SJeffrey Lin 	u8 x_res;		/* units/mm */
119*48a2b783SJeffrey Lin 	u8 y_res;		/* units/mm */
120*48a2b783SJeffrey Lin };
121*48a2b783SJeffrey Lin 
122*48a2b783SJeffrey Lin /* struct raydium_data - represents state of Raydium touchscreen device */
123*48a2b783SJeffrey Lin struct raydium_data {
124*48a2b783SJeffrey Lin 	struct i2c_client *client;
125*48a2b783SJeffrey Lin 	struct input_dev *input;
126*48a2b783SJeffrey Lin 
127*48a2b783SJeffrey Lin 	struct regulator *avdd;
128*48a2b783SJeffrey Lin 	struct regulator *vccio;
129*48a2b783SJeffrey Lin 	struct gpio_desc *reset_gpio;
130*48a2b783SJeffrey Lin 
131*48a2b783SJeffrey Lin 	struct raydium_info info;
132*48a2b783SJeffrey Lin 
133*48a2b783SJeffrey Lin 	struct mutex sysfs_mutex;
134*48a2b783SJeffrey Lin 
135*48a2b783SJeffrey Lin 	u8 *report_data;
136*48a2b783SJeffrey Lin 
137*48a2b783SJeffrey Lin 	u32 data_bank_addr;
138*48a2b783SJeffrey Lin 	u8 report_size;
139*48a2b783SJeffrey Lin 	u8 contact_size;
140*48a2b783SJeffrey Lin 
141*48a2b783SJeffrey Lin 	enum raydium_boot_mode boot_mode;
142*48a2b783SJeffrey Lin 
143*48a2b783SJeffrey Lin 	bool wake_irq_enabled;
144*48a2b783SJeffrey Lin };
145*48a2b783SJeffrey Lin 
146*48a2b783SJeffrey Lin static int raydium_i2c_send(struct i2c_client *client,
147*48a2b783SJeffrey Lin 			    u8 addr, const void *data, size_t len)
148*48a2b783SJeffrey Lin {
149*48a2b783SJeffrey Lin 	u8 *buf;
150*48a2b783SJeffrey Lin 	int tries = 0;
151*48a2b783SJeffrey Lin 	int ret;
152*48a2b783SJeffrey Lin 
153*48a2b783SJeffrey Lin 	buf = kmalloc(len + 1, GFP_KERNEL);
154*48a2b783SJeffrey Lin 	if (!buf)
155*48a2b783SJeffrey Lin 		return -ENOMEM;
156*48a2b783SJeffrey Lin 
157*48a2b783SJeffrey Lin 	buf[0] = addr;
158*48a2b783SJeffrey Lin 	memcpy(buf + 1, data, len);
159*48a2b783SJeffrey Lin 
160*48a2b783SJeffrey Lin 	do {
161*48a2b783SJeffrey Lin 		ret = i2c_master_send(client, buf, len + 1);
162*48a2b783SJeffrey Lin 		if (likely(ret == len + 1))
163*48a2b783SJeffrey Lin 			break;
164*48a2b783SJeffrey Lin 
165*48a2b783SJeffrey Lin 		msleep(20);
166*48a2b783SJeffrey Lin 	} while (++tries < RM_MAX_RETRIES);
167*48a2b783SJeffrey Lin 
168*48a2b783SJeffrey Lin 	kfree(buf);
169*48a2b783SJeffrey Lin 
170*48a2b783SJeffrey Lin 	if (unlikely(ret != len + 1)) {
171*48a2b783SJeffrey Lin 		if (ret >= 0)
172*48a2b783SJeffrey Lin 			ret = -EIO;
173*48a2b783SJeffrey Lin 		dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
174*48a2b783SJeffrey Lin 		return ret;
175*48a2b783SJeffrey Lin 	}
176*48a2b783SJeffrey Lin 
177*48a2b783SJeffrey Lin 	return 0;
178*48a2b783SJeffrey Lin }
179*48a2b783SJeffrey Lin 
180*48a2b783SJeffrey Lin static int raydium_i2c_read(struct i2c_client *client,
181*48a2b783SJeffrey Lin 			    u8 addr, void *data, size_t len)
182*48a2b783SJeffrey Lin {
183*48a2b783SJeffrey Lin 	struct i2c_msg xfer[] = {
184*48a2b783SJeffrey Lin 		{
185*48a2b783SJeffrey Lin 			.addr = client->addr,
186*48a2b783SJeffrey Lin 			.len = 1,
187*48a2b783SJeffrey Lin 			.buf = &addr,
188*48a2b783SJeffrey Lin 		},
189*48a2b783SJeffrey Lin 		{
190*48a2b783SJeffrey Lin 			.addr = client->addr,
191*48a2b783SJeffrey Lin 			.flags = I2C_M_RD,
192*48a2b783SJeffrey Lin 			.len = len,
193*48a2b783SJeffrey Lin 			.buf = data,
194*48a2b783SJeffrey Lin 		}
195*48a2b783SJeffrey Lin 	};
196*48a2b783SJeffrey Lin 	int ret;
197*48a2b783SJeffrey Lin 
198*48a2b783SJeffrey Lin 	ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
199*48a2b783SJeffrey Lin 	if (unlikely(ret != ARRAY_SIZE(xfer)))
200*48a2b783SJeffrey Lin 		return ret < 0 ? ret : -EIO;
201*48a2b783SJeffrey Lin 
202*48a2b783SJeffrey Lin 	return 0;
203*48a2b783SJeffrey Lin }
204*48a2b783SJeffrey Lin 
205*48a2b783SJeffrey Lin static int raydium_i2c_read_message(struct i2c_client *client,
206*48a2b783SJeffrey Lin 				    u32 addr, void *data, size_t len)
207*48a2b783SJeffrey Lin {
208*48a2b783SJeffrey Lin 	__be32 be_addr;
209*48a2b783SJeffrey Lin 	size_t xfer_len;
210*48a2b783SJeffrey Lin 	int error;
211*48a2b783SJeffrey Lin 
212*48a2b783SJeffrey Lin 	while (len) {
213*48a2b783SJeffrey Lin 		xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
214*48a2b783SJeffrey Lin 
215*48a2b783SJeffrey Lin 		be_addr = cpu_to_be32(addr);
216*48a2b783SJeffrey Lin 
217*48a2b783SJeffrey Lin 		error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
218*48a2b783SJeffrey Lin 					 &be_addr, sizeof(be_addr));
219*48a2b783SJeffrey Lin 		if (!error)
220*48a2b783SJeffrey Lin 			error = raydium_i2c_read(client, addr & 0xff,
221*48a2b783SJeffrey Lin 						 data, xfer_len);
222*48a2b783SJeffrey Lin 		if (error)
223*48a2b783SJeffrey Lin 			return error;
224*48a2b783SJeffrey Lin 
225*48a2b783SJeffrey Lin 		len -= xfer_len;
226*48a2b783SJeffrey Lin 		data += xfer_len;
227*48a2b783SJeffrey Lin 		addr += xfer_len;
228*48a2b783SJeffrey Lin 	}
229*48a2b783SJeffrey Lin 
230*48a2b783SJeffrey Lin 	return 0;
231*48a2b783SJeffrey Lin }
232*48a2b783SJeffrey Lin 
233*48a2b783SJeffrey Lin static int raydium_i2c_send_message(struct i2c_client *client,
234*48a2b783SJeffrey Lin 				    u32 addr, const void *data, size_t len)
235*48a2b783SJeffrey Lin {
236*48a2b783SJeffrey Lin 	__be32 be_addr = cpu_to_be32(addr);
237*48a2b783SJeffrey Lin 	int error;
238*48a2b783SJeffrey Lin 
239*48a2b783SJeffrey Lin 	error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
240*48a2b783SJeffrey Lin 				 &be_addr, sizeof(be_addr));
241*48a2b783SJeffrey Lin 	if (!error)
242*48a2b783SJeffrey Lin 		error = raydium_i2c_send(client, addr & 0xff, data, len);
243*48a2b783SJeffrey Lin 
244*48a2b783SJeffrey Lin 	return error;
245*48a2b783SJeffrey Lin }
246*48a2b783SJeffrey Lin 
247*48a2b783SJeffrey Lin static int raydium_i2c_sw_reset(struct i2c_client *client)
248*48a2b783SJeffrey Lin {
249*48a2b783SJeffrey Lin 	const u8 soft_rst_cmd = 0x01;
250*48a2b783SJeffrey Lin 	int error;
251*48a2b783SJeffrey Lin 
252*48a2b783SJeffrey Lin 	error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR,
253*48a2b783SJeffrey Lin 					 &soft_rst_cmd, sizeof(soft_rst_cmd));
254*48a2b783SJeffrey Lin 	if (error) {
255*48a2b783SJeffrey Lin 		dev_err(&client->dev, "software reset failed: %d\n", error);
256*48a2b783SJeffrey Lin 		return error;
257*48a2b783SJeffrey Lin 	}
258*48a2b783SJeffrey Lin 
259*48a2b783SJeffrey Lin 	msleep(RM_RESET_DELAY_MSEC);
260*48a2b783SJeffrey Lin 
261*48a2b783SJeffrey Lin 	return 0;
262*48a2b783SJeffrey Lin }
263*48a2b783SJeffrey Lin 
264*48a2b783SJeffrey Lin static int raydium_i2c_query_ts_info(struct raydium_data *ts)
265*48a2b783SJeffrey Lin {
266*48a2b783SJeffrey Lin 	struct i2c_client *client = ts->client;
267*48a2b783SJeffrey Lin 	struct raydium_data_info data_info;
268*48a2b783SJeffrey Lin 	__le32 query_bank_addr;
269*48a2b783SJeffrey Lin 
270*48a2b783SJeffrey Lin 	int error, retry_cnt;
271*48a2b783SJeffrey Lin 
272*48a2b783SJeffrey Lin 	for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) {
273*48a2b783SJeffrey Lin 		error = raydium_i2c_read(client, RM_CMD_DATA_BANK,
274*48a2b783SJeffrey Lin 					 &data_info, sizeof(data_info));
275*48a2b783SJeffrey Lin 		if (error)
276*48a2b783SJeffrey Lin 			continue;
277*48a2b783SJeffrey Lin 
278*48a2b783SJeffrey Lin 		/*
279*48a2b783SJeffrey Lin 		 * Warn user if we already allocated memory for reports and
280*48a2b783SJeffrey Lin 		 * then the size changed (due to firmware update?) and keep
281*48a2b783SJeffrey Lin 		 * old size instead.
282*48a2b783SJeffrey Lin 		 */
283*48a2b783SJeffrey Lin 		if (ts->report_data && ts->report_size != data_info.pkg_size)
284*48a2b783SJeffrey Lin 			dev_warn(&client->dev,
285*48a2b783SJeffrey Lin 				 "report size changes, was: %d, new: %d\n",
286*48a2b783SJeffrey Lin 				 ts->report_size, data_info.pkg_size);
287*48a2b783SJeffrey Lin 		else
288*48a2b783SJeffrey Lin 			ts->report_size = data_info.pkg_size;
289*48a2b783SJeffrey Lin 
290*48a2b783SJeffrey Lin 		ts->contact_size = data_info.tp_info_size;
291*48a2b783SJeffrey Lin 		ts->data_bank_addr = le32_to_cpu(data_info.data_bank_addr);
292*48a2b783SJeffrey Lin 
293*48a2b783SJeffrey Lin 		dev_dbg(&client->dev,
294*48a2b783SJeffrey Lin 			"data_bank_addr: %#08x, report_size: %d, contact_size: %d\n",
295*48a2b783SJeffrey Lin 			ts->data_bank_addr, ts->report_size, ts->contact_size);
296*48a2b783SJeffrey Lin 
297*48a2b783SJeffrey Lin 		error = raydium_i2c_read(client, RM_CMD_QUERY_BANK,
298*48a2b783SJeffrey Lin 					 &query_bank_addr,
299*48a2b783SJeffrey Lin 					 sizeof(query_bank_addr));
300*48a2b783SJeffrey Lin 		if (error)
301*48a2b783SJeffrey Lin 			continue;
302*48a2b783SJeffrey Lin 
303*48a2b783SJeffrey Lin 		error = raydium_i2c_read_message(client,
304*48a2b783SJeffrey Lin 						 le32_to_cpu(query_bank_addr),
305*48a2b783SJeffrey Lin 						 &ts->info, sizeof(ts->info));
306*48a2b783SJeffrey Lin 		if (error)
307*48a2b783SJeffrey Lin 			continue;
308*48a2b783SJeffrey Lin 
309*48a2b783SJeffrey Lin 		return 0;
310*48a2b783SJeffrey Lin 	}
311*48a2b783SJeffrey Lin 
312*48a2b783SJeffrey Lin 	dev_err(&client->dev, "failed to query device parameters: %d\n", error);
313*48a2b783SJeffrey Lin 	return error;
314*48a2b783SJeffrey Lin }
315*48a2b783SJeffrey Lin 
316*48a2b783SJeffrey Lin static int raydium_i2c_check_fw_status(struct raydium_data *ts)
317*48a2b783SJeffrey Lin {
318*48a2b783SJeffrey Lin 	struct i2c_client *client = ts->client;
319*48a2b783SJeffrey Lin 	static const u8 bl_ack = 0x62;
320*48a2b783SJeffrey Lin 	static const u8 main_ack = 0x66;
321*48a2b783SJeffrey Lin 	u8 buf[4];
322*48a2b783SJeffrey Lin 	int error;
323*48a2b783SJeffrey Lin 
324*48a2b783SJeffrey Lin 	error = raydium_i2c_read(client, RM_CMD_BOOT_READ, buf, sizeof(buf));
325*48a2b783SJeffrey Lin 	if (!error) {
326*48a2b783SJeffrey Lin 		if (buf[0] == bl_ack)
327*48a2b783SJeffrey Lin 			ts->boot_mode = RAYDIUM_TS_BLDR;
328*48a2b783SJeffrey Lin 		else if (buf[0] == main_ack)
329*48a2b783SJeffrey Lin 			ts->boot_mode = RAYDIUM_TS_MAIN;
330*48a2b783SJeffrey Lin 		return 0;
331*48a2b783SJeffrey Lin 	}
332*48a2b783SJeffrey Lin 
333*48a2b783SJeffrey Lin 	return error;
334*48a2b783SJeffrey Lin }
335*48a2b783SJeffrey Lin 
336*48a2b783SJeffrey Lin static int raydium_i2c_initialize(struct raydium_data *ts)
337*48a2b783SJeffrey Lin {
338*48a2b783SJeffrey Lin 	struct i2c_client *client = ts->client;
339*48a2b783SJeffrey Lin 	int error, retry_cnt;
340*48a2b783SJeffrey Lin 
341*48a2b783SJeffrey Lin 	for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) {
342*48a2b783SJeffrey Lin 		/* Wait for Hello packet */
343*48a2b783SJeffrey Lin 		msleep(RM_BOOT_DELAY_MS);
344*48a2b783SJeffrey Lin 
345*48a2b783SJeffrey Lin 		error = raydium_i2c_check_fw_status(ts);
346*48a2b783SJeffrey Lin 		if (error) {
347*48a2b783SJeffrey Lin 			dev_err(&client->dev,
348*48a2b783SJeffrey Lin 				"failed to read 'hello' packet: %d\n", error);
349*48a2b783SJeffrey Lin 			continue;
350*48a2b783SJeffrey Lin 		}
351*48a2b783SJeffrey Lin 
352*48a2b783SJeffrey Lin 		if (ts->boot_mode == RAYDIUM_TS_BLDR ||
353*48a2b783SJeffrey Lin 		    ts->boot_mode == RAYDIUM_TS_MAIN) {
354*48a2b783SJeffrey Lin 			break;
355*48a2b783SJeffrey Lin 		}
356*48a2b783SJeffrey Lin 	}
357*48a2b783SJeffrey Lin 
358*48a2b783SJeffrey Lin 	if (error)
359*48a2b783SJeffrey Lin 		ts->boot_mode = RAYDIUM_TS_BLDR;
360*48a2b783SJeffrey Lin 
361*48a2b783SJeffrey Lin 	if (ts->boot_mode == RAYDIUM_TS_BLDR) {
362*48a2b783SJeffrey Lin 		ts->info.hw_ver = cpu_to_le32(0xffffffffUL);
363*48a2b783SJeffrey Lin 		ts->info.main_ver = 0xff;
364*48a2b783SJeffrey Lin 		ts->info.sub_ver = 0xff;
365*48a2b783SJeffrey Lin 	} else {
366*48a2b783SJeffrey Lin 		raydium_i2c_query_ts_info(ts);
367*48a2b783SJeffrey Lin 	}
368*48a2b783SJeffrey Lin 
369*48a2b783SJeffrey Lin 	return error;
370*48a2b783SJeffrey Lin }
371*48a2b783SJeffrey Lin 
372*48a2b783SJeffrey Lin static int raydium_i2c_bl_chk_state(struct i2c_client *client,
373*48a2b783SJeffrey Lin 				    enum raydium_bl_ack state)
374*48a2b783SJeffrey Lin {
375*48a2b783SJeffrey Lin 	static const u8 ack_ok[] = { 0xFF, 0x39, 0x30, 0x30, 0x54 };
376*48a2b783SJeffrey Lin 	u8 rbuf[sizeof(ack_ok)];
377*48a2b783SJeffrey Lin 	u8 retry;
378*48a2b783SJeffrey Lin 	int error;
379*48a2b783SJeffrey Lin 
380*48a2b783SJeffrey Lin 	for (retry = 0; retry < RM_MAX_FW_RETRIES; retry++) {
381*48a2b783SJeffrey Lin 		switch (state) {
382*48a2b783SJeffrey Lin 		case RAYDIUM_ACK_NULL:
383*48a2b783SJeffrey Lin 			return 0;
384*48a2b783SJeffrey Lin 
385*48a2b783SJeffrey Lin 		case RAYDIUM_WAIT_READY:
386*48a2b783SJeffrey Lin 			error = raydium_i2c_read(client, RM_CMD_BOOT_CHK,
387*48a2b783SJeffrey Lin 						 &rbuf[0], 1);
388*48a2b783SJeffrey Lin 			if (!error && rbuf[0] == RM_BOOT_RDY)
389*48a2b783SJeffrey Lin 				return 0;
390*48a2b783SJeffrey Lin 
391*48a2b783SJeffrey Lin 			break;
392*48a2b783SJeffrey Lin 
393*48a2b783SJeffrey Lin 		case RAYDIUM_PATH_READY:
394*48a2b783SJeffrey Lin 			error = raydium_i2c_read(client, RM_CMD_BOOT_CHK,
395*48a2b783SJeffrey Lin 						 rbuf, sizeof(rbuf));
396*48a2b783SJeffrey Lin 			if (!error && !memcmp(rbuf, ack_ok, sizeof(ack_ok)))
397*48a2b783SJeffrey Lin 				return 0;
398*48a2b783SJeffrey Lin 
399*48a2b783SJeffrey Lin 			break;
400*48a2b783SJeffrey Lin 
401*48a2b783SJeffrey Lin 		default:
402*48a2b783SJeffrey Lin 			dev_err(&client->dev, "%s: invalid target state %d\n",
403*48a2b783SJeffrey Lin 				__func__, state);
404*48a2b783SJeffrey Lin 			return -EINVAL;
405*48a2b783SJeffrey Lin 		}
406*48a2b783SJeffrey Lin 
407*48a2b783SJeffrey Lin 		msleep(20);
408*48a2b783SJeffrey Lin 	}
409*48a2b783SJeffrey Lin 
410*48a2b783SJeffrey Lin 	return -ETIMEDOUT;
411*48a2b783SJeffrey Lin }
412*48a2b783SJeffrey Lin 
413*48a2b783SJeffrey Lin static int raydium_i2c_write_object(struct i2c_client *client,
414*48a2b783SJeffrey Lin 				    const void *data, size_t len,
415*48a2b783SJeffrey Lin 				    enum raydium_bl_ack state)
416*48a2b783SJeffrey Lin {
417*48a2b783SJeffrey Lin 	int error;
418*48a2b783SJeffrey Lin 
419*48a2b783SJeffrey Lin 	error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
420*48a2b783SJeffrey Lin 	if (error) {
421*48a2b783SJeffrey Lin 		dev_err(&client->dev, "WRT obj command failed: %d\n",
422*48a2b783SJeffrey Lin 			error);
423*48a2b783SJeffrey Lin 		return error;
424*48a2b783SJeffrey Lin 	}
425*48a2b783SJeffrey Lin 
426*48a2b783SJeffrey Lin 	error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0);
427*48a2b783SJeffrey Lin 	if (error) {
428*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Ack obj command failed: %d\n", error);
429*48a2b783SJeffrey Lin 		return error;
430*48a2b783SJeffrey Lin 	}
431*48a2b783SJeffrey Lin 
432*48a2b783SJeffrey Lin 	error = raydium_i2c_bl_chk_state(client, state);
433*48a2b783SJeffrey Lin 	if (error) {
434*48a2b783SJeffrey Lin 		dev_err(&client->dev, "BL check state failed: %d\n", error);
435*48a2b783SJeffrey Lin 		return error;
436*48a2b783SJeffrey Lin 	}
437*48a2b783SJeffrey Lin 	return 0;
438*48a2b783SJeffrey Lin }
439*48a2b783SJeffrey Lin 
440*48a2b783SJeffrey Lin static bool raydium_i2c_boot_trigger(struct i2c_client *client)
441*48a2b783SJeffrey Lin {
442*48a2b783SJeffrey Lin 	static const u8 cmd[7][6] = {
443*48a2b783SJeffrey Lin 		{ 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 },
444*48a2b783SJeffrey Lin 		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 },
445*48a2b783SJeffrey Lin 		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0x00 },
446*48a2b783SJeffrey Lin 		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 },
447*48a2b783SJeffrey Lin 		{ 0x08, 0x0C, 0x09, 0x00, 0x50, 0x00 },
448*48a2b783SJeffrey Lin 		{ 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
449*48a2b783SJeffrey Lin 		{ 0x02, 0xA2, 0x00, 0x00, 0x00, 0x00 },
450*48a2b783SJeffrey Lin 	};
451*48a2b783SJeffrey Lin 	int i;
452*48a2b783SJeffrey Lin 	int error;
453*48a2b783SJeffrey Lin 
454*48a2b783SJeffrey Lin 	for (i = 0; i < 7; i++) {
455*48a2b783SJeffrey Lin 		error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]),
456*48a2b783SJeffrey Lin 						 RAYDIUM_WAIT_READY);
457*48a2b783SJeffrey Lin 		if (error) {
458*48a2b783SJeffrey Lin 			dev_err(&client->dev,
459*48a2b783SJeffrey Lin 				"boot trigger failed at step %d: %d\n",
460*48a2b783SJeffrey Lin 				i, error);
461*48a2b783SJeffrey Lin 			return error;
462*48a2b783SJeffrey Lin 		}
463*48a2b783SJeffrey Lin 	}
464*48a2b783SJeffrey Lin 
465*48a2b783SJeffrey Lin 	return 0;
466*48a2b783SJeffrey Lin }
467*48a2b783SJeffrey Lin 
468*48a2b783SJeffrey Lin static bool raydium_i2c_fw_trigger(struct i2c_client *client)
469*48a2b783SJeffrey Lin {
470*48a2b783SJeffrey Lin 	static const u8 cmd[5][11] = {
471*48a2b783SJeffrey Lin 		{ 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 },
472*48a2b783SJeffrey Lin 		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 },
473*48a2b783SJeffrey Lin 		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 },
474*48a2b783SJeffrey Lin 		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 },
475*48a2b783SJeffrey Lin 		{ 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 },
476*48a2b783SJeffrey Lin 	};
477*48a2b783SJeffrey Lin 	int i;
478*48a2b783SJeffrey Lin 	int error;
479*48a2b783SJeffrey Lin 
480*48a2b783SJeffrey Lin 	for (i = 0; i < 5; i++) {
481*48a2b783SJeffrey Lin 		error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]),
482*48a2b783SJeffrey Lin 						 RAYDIUM_ACK_NULL);
483*48a2b783SJeffrey Lin 		if (error) {
484*48a2b783SJeffrey Lin 			dev_err(&client->dev,
485*48a2b783SJeffrey Lin 				"fw trigger failed at step %d: %d\n",
486*48a2b783SJeffrey Lin 				i, error);
487*48a2b783SJeffrey Lin 			return error;
488*48a2b783SJeffrey Lin 		}
489*48a2b783SJeffrey Lin 	}
490*48a2b783SJeffrey Lin 
491*48a2b783SJeffrey Lin 	return 0;
492*48a2b783SJeffrey Lin }
493*48a2b783SJeffrey Lin 
494*48a2b783SJeffrey Lin static int raydium_i2c_check_path(struct i2c_client *client)
495*48a2b783SJeffrey Lin {
496*48a2b783SJeffrey Lin 	static const u8 cmd[] = { 0x09, 0x00, 0x09, 0x00, 0x50, 0x10, 0x00 };
497*48a2b783SJeffrey Lin 	int error;
498*48a2b783SJeffrey Lin 
499*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client, cmd, sizeof(cmd),
500*48a2b783SJeffrey Lin 					 RAYDIUM_PATH_READY);
501*48a2b783SJeffrey Lin 	if (error) {
502*48a2b783SJeffrey Lin 		dev_err(&client->dev, "check path command failed: %d\n", error);
503*48a2b783SJeffrey Lin 		return error;
504*48a2b783SJeffrey Lin 	}
505*48a2b783SJeffrey Lin 
506*48a2b783SJeffrey Lin 	return 0;
507*48a2b783SJeffrey Lin }
508*48a2b783SJeffrey Lin 
509*48a2b783SJeffrey Lin static int raydium_i2c_enter_bl(struct i2c_client *client)
510*48a2b783SJeffrey Lin {
511*48a2b783SJeffrey Lin 	static const u8 cal_cmd[] = { 0x00, 0x01, 0x52 };
512*48a2b783SJeffrey Lin 	int error;
513*48a2b783SJeffrey Lin 
514*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd),
515*48a2b783SJeffrey Lin 					 RAYDIUM_ACK_NULL);
516*48a2b783SJeffrey Lin 	if (error) {
517*48a2b783SJeffrey Lin 		dev_err(&client->dev, "enter bl command failed: %d\n", error);
518*48a2b783SJeffrey Lin 		return error;
519*48a2b783SJeffrey Lin 	}
520*48a2b783SJeffrey Lin 
521*48a2b783SJeffrey Lin 	msleep(RM_BOOT_DELAY_MS);
522*48a2b783SJeffrey Lin 	return 0;
523*48a2b783SJeffrey Lin }
524*48a2b783SJeffrey Lin 
525*48a2b783SJeffrey Lin static int raydium_i2c_leave_bl(struct i2c_client *client)
526*48a2b783SJeffrey Lin {
527*48a2b783SJeffrey Lin 	static const u8 leave_cmd[] = { 0x05, 0x00 };
528*48a2b783SJeffrey Lin 	int error;
529*48a2b783SJeffrey Lin 
530*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client, leave_cmd, sizeof(leave_cmd),
531*48a2b783SJeffrey Lin 					 RAYDIUM_ACK_NULL);
532*48a2b783SJeffrey Lin 	if (error) {
533*48a2b783SJeffrey Lin 		dev_err(&client->dev, "leave bl command failed: %d\n", error);
534*48a2b783SJeffrey Lin 		return error;
535*48a2b783SJeffrey Lin 	}
536*48a2b783SJeffrey Lin 
537*48a2b783SJeffrey Lin 	msleep(RM_BOOT_DELAY_MS);
538*48a2b783SJeffrey Lin 	return 0;
539*48a2b783SJeffrey Lin }
540*48a2b783SJeffrey Lin 
541*48a2b783SJeffrey Lin static int raydium_i2c_write_checksum(struct i2c_client *client,
542*48a2b783SJeffrey Lin 				      size_t length, u16 checksum)
543*48a2b783SJeffrey Lin {
544*48a2b783SJeffrey Lin 	u8 checksum_cmd[] = { 0x00, 0x05, 0x6D, 0x00, 0x00, 0x00, 0x00 };
545*48a2b783SJeffrey Lin 	int error;
546*48a2b783SJeffrey Lin 
547*48a2b783SJeffrey Lin 	put_unaligned_le16(length, &checksum_cmd[3]);
548*48a2b783SJeffrey Lin 	put_unaligned_le16(checksum, &checksum_cmd[5]);
549*48a2b783SJeffrey Lin 
550*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client,
551*48a2b783SJeffrey Lin 					 checksum_cmd, sizeof(checksum_cmd),
552*48a2b783SJeffrey Lin 					 RAYDIUM_ACK_NULL);
553*48a2b783SJeffrey Lin 	if (error) {
554*48a2b783SJeffrey Lin 		dev_err(&client->dev, "failed to write checksum: %d\n",
555*48a2b783SJeffrey Lin 			error);
556*48a2b783SJeffrey Lin 		return error;
557*48a2b783SJeffrey Lin 	}
558*48a2b783SJeffrey Lin 
559*48a2b783SJeffrey Lin 	return 0;
560*48a2b783SJeffrey Lin }
561*48a2b783SJeffrey Lin 
562*48a2b783SJeffrey Lin static int raydium_i2c_disable_watch_dog(struct i2c_client *client)
563*48a2b783SJeffrey Lin {
564*48a2b783SJeffrey Lin 	static const u8 cmd[] = { 0x0A, 0xAA };
565*48a2b783SJeffrey Lin 	int error;
566*48a2b783SJeffrey Lin 
567*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client, cmd, sizeof(cmd),
568*48a2b783SJeffrey Lin 					 RAYDIUM_WAIT_READY);
569*48a2b783SJeffrey Lin 	if (error) {
570*48a2b783SJeffrey Lin 		dev_err(&client->dev, "disable watchdog command failed: %d\n",
571*48a2b783SJeffrey Lin 			error);
572*48a2b783SJeffrey Lin 		return error;
573*48a2b783SJeffrey Lin 	}
574*48a2b783SJeffrey Lin 
575*48a2b783SJeffrey Lin 	return 0;
576*48a2b783SJeffrey Lin }
577*48a2b783SJeffrey Lin 
578*48a2b783SJeffrey Lin static int raydium_i2c_fw_write_page(struct i2c_client *client,
579*48a2b783SJeffrey Lin 				     u16 page_idx, const void *data, size_t len)
580*48a2b783SJeffrey Lin {
581*48a2b783SJeffrey Lin 	u8 buf[RM_BL_WRT_LEN];
582*48a2b783SJeffrey Lin 	size_t xfer_len;
583*48a2b783SJeffrey Lin 	int error;
584*48a2b783SJeffrey Lin 	int i;
585*48a2b783SJeffrey Lin 
586*48a2b783SJeffrey Lin 	BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0);
587*48a2b783SJeffrey Lin 
588*48a2b783SJeffrey Lin 	for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) {
589*48a2b783SJeffrey Lin 		buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT;
590*48a2b783SJeffrey Lin 		buf[BL_PAGE_STR] = page_idx ? 0xff : 0;
591*48a2b783SJeffrey Lin 		buf[BL_PKG_IDX] = i + 1;
592*48a2b783SJeffrey Lin 
593*48a2b783SJeffrey Lin 		xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE);
594*48a2b783SJeffrey Lin 		memcpy(&buf[BL_DATA_STR], data, xfer_len);
595*48a2b783SJeffrey Lin 		if (len < RM_BL_WRT_PKG_SIZE)
596*48a2b783SJeffrey Lin 			memset(&buf[BL_DATA_STR + xfer_len], 0xff,
597*48a2b783SJeffrey Lin 				RM_BL_WRT_PKG_SIZE - xfer_len);
598*48a2b783SJeffrey Lin 
599*48a2b783SJeffrey Lin 		error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN,
600*48a2b783SJeffrey Lin 						 RAYDIUM_WAIT_READY);
601*48a2b783SJeffrey Lin 		if (error) {
602*48a2b783SJeffrey Lin 			dev_err(&client->dev,
603*48a2b783SJeffrey Lin 				"page write command failed for page %d, chunk %d: %d\n",
604*48a2b783SJeffrey Lin 				page_idx, i, error);
605*48a2b783SJeffrey Lin 			return error;
606*48a2b783SJeffrey Lin 		}
607*48a2b783SJeffrey Lin 
608*48a2b783SJeffrey Lin 		data += xfer_len;
609*48a2b783SJeffrey Lin 		len -= xfer_len;
610*48a2b783SJeffrey Lin 	}
611*48a2b783SJeffrey Lin 
612*48a2b783SJeffrey Lin 	return error;
613*48a2b783SJeffrey Lin }
614*48a2b783SJeffrey Lin 
615*48a2b783SJeffrey Lin static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
616*48a2b783SJeffrey Lin 					 const struct firmware *fw)
617*48a2b783SJeffrey Lin {
618*48a2b783SJeffrey Lin 	struct i2c_client *client = ts->client;
619*48a2b783SJeffrey Lin 	const void *data;
620*48a2b783SJeffrey Lin 	size_t data_len;
621*48a2b783SJeffrey Lin 	size_t len;
622*48a2b783SJeffrey Lin 	int page_nr;
623*48a2b783SJeffrey Lin 	int i;
624*48a2b783SJeffrey Lin 	int error;
625*48a2b783SJeffrey Lin 	u16 fw_checksum;
626*48a2b783SJeffrey Lin 
627*48a2b783SJeffrey Lin 	if (fw->size == 0 || fw->size > RM_MAX_FW_SIZE) {
628*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Invalid firmware length\n");
629*48a2b783SJeffrey Lin 		return -EINVAL;
630*48a2b783SJeffrey Lin 	}
631*48a2b783SJeffrey Lin 
632*48a2b783SJeffrey Lin 	error = raydium_i2c_check_fw_status(ts);
633*48a2b783SJeffrey Lin 	if (error) {
634*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Unable to access IC %d\n", error);
635*48a2b783SJeffrey Lin 		return error;
636*48a2b783SJeffrey Lin 	}
637*48a2b783SJeffrey Lin 
638*48a2b783SJeffrey Lin 	if (ts->boot_mode == RAYDIUM_TS_MAIN) {
639*48a2b783SJeffrey Lin 		for (i = 0; i < RM_MAX_RETRIES; i++) {
640*48a2b783SJeffrey Lin 			error = raydium_i2c_enter_bl(client);
641*48a2b783SJeffrey Lin 			if (!error) {
642*48a2b783SJeffrey Lin 				error = raydium_i2c_check_fw_status(ts);
643*48a2b783SJeffrey Lin 				if (error) {
644*48a2b783SJeffrey Lin 					dev_err(&client->dev,
645*48a2b783SJeffrey Lin 						"unable to access IC: %d\n",
646*48a2b783SJeffrey Lin 						error);
647*48a2b783SJeffrey Lin 					return error;
648*48a2b783SJeffrey Lin 				}
649*48a2b783SJeffrey Lin 
650*48a2b783SJeffrey Lin 				if (ts->boot_mode == RAYDIUM_TS_BLDR)
651*48a2b783SJeffrey Lin 					break;
652*48a2b783SJeffrey Lin 			}
653*48a2b783SJeffrey Lin 		}
654*48a2b783SJeffrey Lin 
655*48a2b783SJeffrey Lin 		if (ts->boot_mode == RAYDIUM_TS_MAIN) {
656*48a2b783SJeffrey Lin 			dev_err(&client->dev,
657*48a2b783SJeffrey Lin 				"failied to jump to boot loader: %d\n",
658*48a2b783SJeffrey Lin 				error);
659*48a2b783SJeffrey Lin 			return -EIO;
660*48a2b783SJeffrey Lin 		}
661*48a2b783SJeffrey Lin 	}
662*48a2b783SJeffrey Lin 
663*48a2b783SJeffrey Lin 	error = raydium_i2c_disable_watch_dog(client);
664*48a2b783SJeffrey Lin 	if (error)
665*48a2b783SJeffrey Lin 		return error;
666*48a2b783SJeffrey Lin 
667*48a2b783SJeffrey Lin 	error = raydium_i2c_check_path(client);
668*48a2b783SJeffrey Lin 	if (error)
669*48a2b783SJeffrey Lin 		return error;
670*48a2b783SJeffrey Lin 
671*48a2b783SJeffrey Lin 	error = raydium_i2c_boot_trigger(client);
672*48a2b783SJeffrey Lin 	if (error) {
673*48a2b783SJeffrey Lin 		dev_err(&client->dev, "send boot trigger fail: %d\n", error);
674*48a2b783SJeffrey Lin 		return error;
675*48a2b783SJeffrey Lin 	}
676*48a2b783SJeffrey Lin 
677*48a2b783SJeffrey Lin 	msleep(RM_BOOT_DELAY_MS);
678*48a2b783SJeffrey Lin 
679*48a2b783SJeffrey Lin 	data = fw->data;
680*48a2b783SJeffrey Lin 	data_len = fw->size;
681*48a2b783SJeffrey Lin 	page_nr = 0;
682*48a2b783SJeffrey Lin 
683*48a2b783SJeffrey Lin 	while (data_len) {
684*48a2b783SJeffrey Lin 		len = min_t(size_t, data_len, RM_FW_PAGE_SIZE);
685*48a2b783SJeffrey Lin 
686*48a2b783SJeffrey Lin 		error = raydium_i2c_fw_write_page(client, page_nr++, data, len);
687*48a2b783SJeffrey Lin 		if (error)
688*48a2b783SJeffrey Lin 			return error;
689*48a2b783SJeffrey Lin 
690*48a2b783SJeffrey Lin 		msleep(20);
691*48a2b783SJeffrey Lin 
692*48a2b783SJeffrey Lin 		data += len;
693*48a2b783SJeffrey Lin 		data_len -= len;
694*48a2b783SJeffrey Lin 	}
695*48a2b783SJeffrey Lin 
696*48a2b783SJeffrey Lin 	error = raydium_i2c_leave_bl(client);
697*48a2b783SJeffrey Lin 	if (error) {
698*48a2b783SJeffrey Lin 		dev_err(&client->dev,
699*48a2b783SJeffrey Lin 			"failed to leave boot loader: %d\n", error);
700*48a2b783SJeffrey Lin 		return error;
701*48a2b783SJeffrey Lin 	}
702*48a2b783SJeffrey Lin 
703*48a2b783SJeffrey Lin 	dev_dbg(&client->dev, "left boot loader mode\n");
704*48a2b783SJeffrey Lin 	msleep(RM_BOOT_DELAY_MS);
705*48a2b783SJeffrey Lin 
706*48a2b783SJeffrey Lin 	error = raydium_i2c_check_fw_status(ts);
707*48a2b783SJeffrey Lin 	if (error) {
708*48a2b783SJeffrey Lin 		dev_err(&client->dev,
709*48a2b783SJeffrey Lin 			"failed to check fw status after write: %d\n",
710*48a2b783SJeffrey Lin 			error);
711*48a2b783SJeffrey Lin 		return error;
712*48a2b783SJeffrey Lin 	}
713*48a2b783SJeffrey Lin 
714*48a2b783SJeffrey Lin 	if (ts->boot_mode != RAYDIUM_TS_MAIN) {
715*48a2b783SJeffrey Lin 		dev_err(&client->dev,
716*48a2b783SJeffrey Lin 			"failed to switch to main fw after writing firmware: %d\n",
717*48a2b783SJeffrey Lin 			error);
718*48a2b783SJeffrey Lin 		return -EINVAL;
719*48a2b783SJeffrey Lin 	}
720*48a2b783SJeffrey Lin 
721*48a2b783SJeffrey Lin 	error = raydium_i2c_fw_trigger(client);
722*48a2b783SJeffrey Lin 	if (error) {
723*48a2b783SJeffrey Lin 		dev_err(&client->dev, "failed to trigger fw: %d\n", error);
724*48a2b783SJeffrey Lin 		return error;
725*48a2b783SJeffrey Lin 	}
726*48a2b783SJeffrey Lin 
727*48a2b783SJeffrey Lin 	fw_checksum = 0;
728*48a2b783SJeffrey Lin 	for (i = 0; i < fw->size; i++)
729*48a2b783SJeffrey Lin 		fw_checksum += fw->data[i];
730*48a2b783SJeffrey Lin 
731*48a2b783SJeffrey Lin 	error = raydium_i2c_write_checksum(client, fw->size, fw_checksum);
732*48a2b783SJeffrey Lin 	if (error)
733*48a2b783SJeffrey Lin 		return error;
734*48a2b783SJeffrey Lin 
735*48a2b783SJeffrey Lin 	return 0;
736*48a2b783SJeffrey Lin }
737*48a2b783SJeffrey Lin 
738*48a2b783SJeffrey Lin static int raydium_i2c_fw_update(struct raydium_data *ts)
739*48a2b783SJeffrey Lin {
740*48a2b783SJeffrey Lin 	struct i2c_client *client = ts->client;
741*48a2b783SJeffrey Lin 	const struct firmware *fw = NULL;
742*48a2b783SJeffrey Lin 	const char *fw_file = "raydium.fw";
743*48a2b783SJeffrey Lin 	int error;
744*48a2b783SJeffrey Lin 
745*48a2b783SJeffrey Lin 	error = request_firmware(&fw, fw_file, &client->dev);
746*48a2b783SJeffrey Lin 	if (error) {
747*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Unable to open firmware %s\n", fw_file);
748*48a2b783SJeffrey Lin 		return error;
749*48a2b783SJeffrey Lin 	}
750*48a2b783SJeffrey Lin 
751*48a2b783SJeffrey Lin 	disable_irq(client->irq);
752*48a2b783SJeffrey Lin 
753*48a2b783SJeffrey Lin 	error = raydium_i2c_do_update_firmware(ts, fw);
754*48a2b783SJeffrey Lin 	if (error) {
755*48a2b783SJeffrey Lin 		dev_err(&client->dev, "firmware update failed: %d\n", error);
756*48a2b783SJeffrey Lin 		ts->boot_mode = RAYDIUM_TS_BLDR;
757*48a2b783SJeffrey Lin 		goto out_enable_irq;
758*48a2b783SJeffrey Lin 	}
759*48a2b783SJeffrey Lin 
760*48a2b783SJeffrey Lin 	error = raydium_i2c_initialize(ts);
761*48a2b783SJeffrey Lin 	if (error) {
762*48a2b783SJeffrey Lin 		dev_err(&client->dev,
763*48a2b783SJeffrey Lin 			"failed to initialize device after firmware update: %d\n",
764*48a2b783SJeffrey Lin 			error);
765*48a2b783SJeffrey Lin 		ts->boot_mode = RAYDIUM_TS_BLDR;
766*48a2b783SJeffrey Lin 		goto out_enable_irq;
767*48a2b783SJeffrey Lin 	}
768*48a2b783SJeffrey Lin 
769*48a2b783SJeffrey Lin 	ts->boot_mode = RAYDIUM_TS_MAIN;
770*48a2b783SJeffrey Lin 
771*48a2b783SJeffrey Lin out_enable_irq:
772*48a2b783SJeffrey Lin 	enable_irq(client->irq);
773*48a2b783SJeffrey Lin 	msleep(100);
774*48a2b783SJeffrey Lin 
775*48a2b783SJeffrey Lin 	release_firmware(fw);
776*48a2b783SJeffrey Lin 
777*48a2b783SJeffrey Lin 	return error;
778*48a2b783SJeffrey Lin }
779*48a2b783SJeffrey Lin 
780*48a2b783SJeffrey Lin static void raydium_mt_event(struct raydium_data *ts)
781*48a2b783SJeffrey Lin {
782*48a2b783SJeffrey Lin 	int i;
783*48a2b783SJeffrey Lin 	int error;
784*48a2b783SJeffrey Lin 
785*48a2b783SJeffrey Lin 	error = raydium_i2c_read_message(ts->client, ts->data_bank_addr,
786*48a2b783SJeffrey Lin 					 ts->report_data, ts->report_size);
787*48a2b783SJeffrey Lin 	if (error) {
788*48a2b783SJeffrey Lin 		dev_err(&ts->client->dev, "%s: failed to read data: %d\n",
789*48a2b783SJeffrey Lin 			__func__, error);
790*48a2b783SJeffrey Lin 		return;
791*48a2b783SJeffrey Lin 	}
792*48a2b783SJeffrey Lin 
793*48a2b783SJeffrey Lin 	for (i = 0; i < ts->report_size / ts->contact_size; i++) {
794*48a2b783SJeffrey Lin 		u8 *contact = &ts->report_data[ts->contact_size * i];
795*48a2b783SJeffrey Lin 		bool state = contact[RM_CONTACT_STATE_POS];
796*48a2b783SJeffrey Lin 		u8 wx, wy;
797*48a2b783SJeffrey Lin 
798*48a2b783SJeffrey Lin 		input_mt_slot(ts->input, i);
799*48a2b783SJeffrey Lin 		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, state);
800*48a2b783SJeffrey Lin 
801*48a2b783SJeffrey Lin 		if (!state)
802*48a2b783SJeffrey Lin 			continue;
803*48a2b783SJeffrey Lin 
804*48a2b783SJeffrey Lin 		input_report_abs(ts->input, ABS_MT_POSITION_X,
805*48a2b783SJeffrey Lin 				get_unaligned_le16(&contact[RM_CONTACT_X_POS]));
806*48a2b783SJeffrey Lin 		input_report_abs(ts->input, ABS_MT_POSITION_Y,
807*48a2b783SJeffrey Lin 				get_unaligned_le16(&contact[RM_CONTACT_Y_POS]));
808*48a2b783SJeffrey Lin 		input_report_abs(ts->input, ABS_MT_PRESSURE,
809*48a2b783SJeffrey Lin 				contact[RM_CONTACT_PRESSURE_POS]);
810*48a2b783SJeffrey Lin 
811*48a2b783SJeffrey Lin 		wx = contact[RM_CONTACT_WIDTH_X_POS];
812*48a2b783SJeffrey Lin 		wy = contact[RM_CONTACT_WIDTH_Y_POS];
813*48a2b783SJeffrey Lin 
814*48a2b783SJeffrey Lin 		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, max(wx, wy));
815*48a2b783SJeffrey Lin 		input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, min(wx, wy));
816*48a2b783SJeffrey Lin 	}
817*48a2b783SJeffrey Lin 
818*48a2b783SJeffrey Lin 	input_mt_sync_frame(ts->input);
819*48a2b783SJeffrey Lin 	input_sync(ts->input);
820*48a2b783SJeffrey Lin }
821*48a2b783SJeffrey Lin 
822*48a2b783SJeffrey Lin static irqreturn_t raydium_i2c_irq(int irq, void *_dev)
823*48a2b783SJeffrey Lin {
824*48a2b783SJeffrey Lin 	struct raydium_data *ts = _dev;
825*48a2b783SJeffrey Lin 
826*48a2b783SJeffrey Lin 	if (ts->boot_mode != RAYDIUM_TS_BLDR)
827*48a2b783SJeffrey Lin 		raydium_mt_event(ts);
828*48a2b783SJeffrey Lin 
829*48a2b783SJeffrey Lin 	return IRQ_HANDLED;
830*48a2b783SJeffrey Lin }
831*48a2b783SJeffrey Lin 
832*48a2b783SJeffrey Lin static ssize_t raydium_i2c_fw_ver_show(struct device *dev,
833*48a2b783SJeffrey Lin 				       struct device_attribute *attr, char *buf)
834*48a2b783SJeffrey Lin {
835*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
836*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
837*48a2b783SJeffrey Lin 
838*48a2b783SJeffrey Lin 	return sprintf(buf, "%d.%d\n", ts->info.main_ver, ts->info.sub_ver);
839*48a2b783SJeffrey Lin }
840*48a2b783SJeffrey Lin 
841*48a2b783SJeffrey Lin static ssize_t raydium_i2c_hw_ver_show(struct device *dev,
842*48a2b783SJeffrey Lin 				       struct device_attribute *attr, char *buf)
843*48a2b783SJeffrey Lin {
844*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
845*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
846*48a2b783SJeffrey Lin 
847*48a2b783SJeffrey Lin 	return sprintf(buf, "%#04x\n", le32_to_cpu(ts->info.hw_ver));
848*48a2b783SJeffrey Lin }
849*48a2b783SJeffrey Lin 
850*48a2b783SJeffrey Lin static ssize_t raydium_i2c_boot_mode_show(struct device *dev,
851*48a2b783SJeffrey Lin 					  struct device_attribute *attr,
852*48a2b783SJeffrey Lin 					  char *buf)
853*48a2b783SJeffrey Lin {
854*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
855*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
856*48a2b783SJeffrey Lin 
857*48a2b783SJeffrey Lin 	return sprintf(buf, "%s\n",
858*48a2b783SJeffrey Lin 		       ts->boot_mode == RAYDIUM_TS_MAIN ?
859*48a2b783SJeffrey Lin 				"Normal" : "Recovery");
860*48a2b783SJeffrey Lin }
861*48a2b783SJeffrey Lin 
862*48a2b783SJeffrey Lin static ssize_t raydium_i2c_update_fw_store(struct device *dev,
863*48a2b783SJeffrey Lin 					   struct device_attribute *attr,
864*48a2b783SJeffrey Lin 					   const char *buf, size_t count)
865*48a2b783SJeffrey Lin {
866*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
867*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
868*48a2b783SJeffrey Lin 	int error;
869*48a2b783SJeffrey Lin 
870*48a2b783SJeffrey Lin 	error = mutex_lock_interruptible(&ts->sysfs_mutex);
871*48a2b783SJeffrey Lin 	if (error)
872*48a2b783SJeffrey Lin 		return error;
873*48a2b783SJeffrey Lin 
874*48a2b783SJeffrey Lin 	error = raydium_i2c_fw_update(ts);
875*48a2b783SJeffrey Lin 
876*48a2b783SJeffrey Lin 	mutex_unlock(&ts->sysfs_mutex);
877*48a2b783SJeffrey Lin 
878*48a2b783SJeffrey Lin 	return error ?: count;
879*48a2b783SJeffrey Lin }
880*48a2b783SJeffrey Lin 
881*48a2b783SJeffrey Lin static ssize_t raydium_i2c_calibrate_store(struct device *dev,
882*48a2b783SJeffrey Lin 					   struct device_attribute *attr,
883*48a2b783SJeffrey Lin 					   const char *buf, size_t count)
884*48a2b783SJeffrey Lin {
885*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
886*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
887*48a2b783SJeffrey Lin 	static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E };
888*48a2b783SJeffrey Lin 	int error;
889*48a2b783SJeffrey Lin 
890*48a2b783SJeffrey Lin 	error = mutex_lock_interruptible(&ts->sysfs_mutex);
891*48a2b783SJeffrey Lin 	if (error)
892*48a2b783SJeffrey Lin 		return error;
893*48a2b783SJeffrey Lin 
894*48a2b783SJeffrey Lin 	error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd),
895*48a2b783SJeffrey Lin 					 RAYDIUM_WAIT_READY);
896*48a2b783SJeffrey Lin 	if (error)
897*48a2b783SJeffrey Lin 		dev_err(&client->dev, "calibrate command failed: %d\n", error);
898*48a2b783SJeffrey Lin 
899*48a2b783SJeffrey Lin 	mutex_unlock(&ts->sysfs_mutex);
900*48a2b783SJeffrey Lin 	return error ?: count;
901*48a2b783SJeffrey Lin }
902*48a2b783SJeffrey Lin 
903*48a2b783SJeffrey Lin static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL);
904*48a2b783SJeffrey Lin static DEVICE_ATTR(hw_version, S_IRUGO, raydium_i2c_hw_ver_show, NULL);
905*48a2b783SJeffrey Lin static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL);
906*48a2b783SJeffrey Lin static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store);
907*48a2b783SJeffrey Lin static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store);
908*48a2b783SJeffrey Lin 
909*48a2b783SJeffrey Lin static struct attribute *raydium_i2c_attributes[] = {
910*48a2b783SJeffrey Lin 	&dev_attr_update_fw.attr,
911*48a2b783SJeffrey Lin 	&dev_attr_boot_mode.attr,
912*48a2b783SJeffrey Lin 	&dev_attr_fw_version.attr,
913*48a2b783SJeffrey Lin 	&dev_attr_hw_version.attr,
914*48a2b783SJeffrey Lin 	&dev_attr_calibrate.attr,
915*48a2b783SJeffrey Lin 	NULL
916*48a2b783SJeffrey Lin };
917*48a2b783SJeffrey Lin 
918*48a2b783SJeffrey Lin static struct attribute_group raydium_i2c_attribute_group = {
919*48a2b783SJeffrey Lin 	.attrs = raydium_i2c_attributes,
920*48a2b783SJeffrey Lin };
921*48a2b783SJeffrey Lin 
922*48a2b783SJeffrey Lin static void raydium_i2c_remove_sysfs_group(void *_data)
923*48a2b783SJeffrey Lin {
924*48a2b783SJeffrey Lin 	struct raydium_data *ts = _data;
925*48a2b783SJeffrey Lin 
926*48a2b783SJeffrey Lin 	sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group);
927*48a2b783SJeffrey Lin }
928*48a2b783SJeffrey Lin 
929*48a2b783SJeffrey Lin static int raydium_i2c_power_on(struct raydium_data *ts)
930*48a2b783SJeffrey Lin {
931*48a2b783SJeffrey Lin 	int error;
932*48a2b783SJeffrey Lin 
933*48a2b783SJeffrey Lin 	if (IS_ERR_OR_NULL(ts->reset_gpio))
934*48a2b783SJeffrey Lin 		return 0;
935*48a2b783SJeffrey Lin 
936*48a2b783SJeffrey Lin 	gpiod_set_value_cansleep(ts->reset_gpio, 1);
937*48a2b783SJeffrey Lin 
938*48a2b783SJeffrey Lin 	error = regulator_enable(ts->avdd);
939*48a2b783SJeffrey Lin 	if (error) {
940*48a2b783SJeffrey Lin 		dev_err(&ts->client->dev,
941*48a2b783SJeffrey Lin 			"failed to enable avdd regulator: %d\n", error);
942*48a2b783SJeffrey Lin 		goto release_reset_gpio;
943*48a2b783SJeffrey Lin 	}
944*48a2b783SJeffrey Lin 
945*48a2b783SJeffrey Lin 	error = regulator_enable(ts->vccio);
946*48a2b783SJeffrey Lin 	if (error) {
947*48a2b783SJeffrey Lin 		regulator_disable(ts->avdd);
948*48a2b783SJeffrey Lin 		dev_err(&ts->client->dev,
949*48a2b783SJeffrey Lin 			"failed to enable vccio regulator: %d\n", error);
950*48a2b783SJeffrey Lin 		goto release_reset_gpio;
951*48a2b783SJeffrey Lin 	}
952*48a2b783SJeffrey Lin 
953*48a2b783SJeffrey Lin 	udelay(RM_POWERON_DELAY_USEC);
954*48a2b783SJeffrey Lin 
955*48a2b783SJeffrey Lin release_reset_gpio:
956*48a2b783SJeffrey Lin 	gpiod_set_value_cansleep(ts->reset_gpio, 0);
957*48a2b783SJeffrey Lin 
958*48a2b783SJeffrey Lin 	if (error)
959*48a2b783SJeffrey Lin 		return error;
960*48a2b783SJeffrey Lin 
961*48a2b783SJeffrey Lin 	msleep(RM_RESET_DELAY_MSEC);
962*48a2b783SJeffrey Lin 
963*48a2b783SJeffrey Lin 	return 0;
964*48a2b783SJeffrey Lin }
965*48a2b783SJeffrey Lin 
966*48a2b783SJeffrey Lin static void raydium_i2c_power_off(void *_data)
967*48a2b783SJeffrey Lin {
968*48a2b783SJeffrey Lin 	struct raydium_data *ts = _data;
969*48a2b783SJeffrey Lin 
970*48a2b783SJeffrey Lin 	if (!IS_ERR_OR_NULL(ts->reset_gpio)) {
971*48a2b783SJeffrey Lin 		gpiod_set_value_cansleep(ts->reset_gpio, 1);
972*48a2b783SJeffrey Lin 		regulator_disable(ts->vccio);
973*48a2b783SJeffrey Lin 		regulator_disable(ts->avdd);
974*48a2b783SJeffrey Lin 	}
975*48a2b783SJeffrey Lin }
976*48a2b783SJeffrey Lin 
977*48a2b783SJeffrey Lin static int raydium_i2c_probe(struct i2c_client *client,
978*48a2b783SJeffrey Lin 			     const struct i2c_device_id *id)
979*48a2b783SJeffrey Lin {
980*48a2b783SJeffrey Lin 	union i2c_smbus_data dummy;
981*48a2b783SJeffrey Lin 	struct raydium_data *ts;
982*48a2b783SJeffrey Lin 	int error;
983*48a2b783SJeffrey Lin 
984*48a2b783SJeffrey Lin 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
985*48a2b783SJeffrey Lin 		dev_err(&client->dev,
986*48a2b783SJeffrey Lin 			"i2c check functionality error (need I2C_FUNC_I2C)\n");
987*48a2b783SJeffrey Lin 		return -ENXIO;
988*48a2b783SJeffrey Lin 	}
989*48a2b783SJeffrey Lin 
990*48a2b783SJeffrey Lin 	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
991*48a2b783SJeffrey Lin 	if (!ts)
992*48a2b783SJeffrey Lin 		return -ENOMEM;
993*48a2b783SJeffrey Lin 
994*48a2b783SJeffrey Lin 	mutex_init(&ts->sysfs_mutex);
995*48a2b783SJeffrey Lin 
996*48a2b783SJeffrey Lin 	ts->client = client;
997*48a2b783SJeffrey Lin 	i2c_set_clientdata(client, ts);
998*48a2b783SJeffrey Lin 
999*48a2b783SJeffrey Lin 	ts->avdd = devm_regulator_get(&client->dev, "avdd");
1000*48a2b783SJeffrey Lin 	if (IS_ERR(ts->avdd)) {
1001*48a2b783SJeffrey Lin 		error = PTR_ERR(ts->avdd);
1002*48a2b783SJeffrey Lin 		if (error != -EPROBE_DEFER)
1003*48a2b783SJeffrey Lin 			dev_err(&client->dev,
1004*48a2b783SJeffrey Lin 				"Failed to get 'avdd' regulator: %d\n", error);
1005*48a2b783SJeffrey Lin 		return error;
1006*48a2b783SJeffrey Lin 	}
1007*48a2b783SJeffrey Lin 
1008*48a2b783SJeffrey Lin 	ts->vccio = devm_regulator_get(&client->dev, "vccio");
1009*48a2b783SJeffrey Lin 	if (IS_ERR(ts->vccio)) {
1010*48a2b783SJeffrey Lin 		error = PTR_ERR(ts->vccio);
1011*48a2b783SJeffrey Lin 		if (error != -EPROBE_DEFER)
1012*48a2b783SJeffrey Lin 			dev_err(&client->dev,
1013*48a2b783SJeffrey Lin 				"Failed to get 'vccio' regulator: %d\n", error);
1014*48a2b783SJeffrey Lin 		return error;
1015*48a2b783SJeffrey Lin 	}
1016*48a2b783SJeffrey Lin 
1017*48a2b783SJeffrey Lin 	ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
1018*48a2b783SJeffrey Lin 						 GPIOD_OUT_LOW);
1019*48a2b783SJeffrey Lin 	if (IS_ERR(ts->reset_gpio)) {
1020*48a2b783SJeffrey Lin 		error = PTR_ERR(ts->reset_gpio);
1021*48a2b783SJeffrey Lin 		if (error != -EPROBE_DEFER) {
1022*48a2b783SJeffrey Lin 			dev_err(&client->dev,
1023*48a2b783SJeffrey Lin 				"failed to get reset gpio: %d\n", error);
1024*48a2b783SJeffrey Lin 			return error;
1025*48a2b783SJeffrey Lin 		}
1026*48a2b783SJeffrey Lin 	}
1027*48a2b783SJeffrey Lin 
1028*48a2b783SJeffrey Lin 	error = raydium_i2c_power_on(ts);
1029*48a2b783SJeffrey Lin 	if (error)
1030*48a2b783SJeffrey Lin 		return error;
1031*48a2b783SJeffrey Lin 
1032*48a2b783SJeffrey Lin 	error = devm_add_action(&client->dev, raydium_i2c_power_off, ts);
1033*48a2b783SJeffrey Lin 	if (error) {
1034*48a2b783SJeffrey Lin 		dev_err(&client->dev,
1035*48a2b783SJeffrey Lin 			"failed to install power off action: %d\n", error);
1036*48a2b783SJeffrey Lin 		raydium_i2c_power_off(ts);
1037*48a2b783SJeffrey Lin 		return error;
1038*48a2b783SJeffrey Lin 	}
1039*48a2b783SJeffrey Lin 
1040*48a2b783SJeffrey Lin 	/* Make sure there is something at this address */
1041*48a2b783SJeffrey Lin 	if (i2c_smbus_xfer(client->adapter, client->addr, 0,
1042*48a2b783SJeffrey Lin 			   I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) {
1043*48a2b783SJeffrey Lin 		dev_err(&client->dev, "nothing at this address\n");
1044*48a2b783SJeffrey Lin 		return -ENXIO;
1045*48a2b783SJeffrey Lin 	}
1046*48a2b783SJeffrey Lin 
1047*48a2b783SJeffrey Lin 	error = raydium_i2c_initialize(ts);
1048*48a2b783SJeffrey Lin 	if (error) {
1049*48a2b783SJeffrey Lin 		dev_err(&client->dev, "failed to initialize: %d\n", error);
1050*48a2b783SJeffrey Lin 		return error;
1051*48a2b783SJeffrey Lin 	}
1052*48a2b783SJeffrey Lin 
1053*48a2b783SJeffrey Lin 	ts->report_data = devm_kmalloc(&client->dev,
1054*48a2b783SJeffrey Lin 				       ts->report_size, GFP_KERNEL);
1055*48a2b783SJeffrey Lin 	if (!ts->report_data)
1056*48a2b783SJeffrey Lin 		return -ENOMEM;
1057*48a2b783SJeffrey Lin 
1058*48a2b783SJeffrey Lin 	ts->input = devm_input_allocate_device(&client->dev);
1059*48a2b783SJeffrey Lin 	if (!ts->input) {
1060*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Failed to allocate input device\n");
1061*48a2b783SJeffrey Lin 		return -ENOMEM;
1062*48a2b783SJeffrey Lin 	}
1063*48a2b783SJeffrey Lin 
1064*48a2b783SJeffrey Lin 	ts->input->name = "Raydium Touchscreen";
1065*48a2b783SJeffrey Lin 	ts->input->id.bustype = BUS_I2C;
1066*48a2b783SJeffrey Lin 
1067*48a2b783SJeffrey Lin 	input_set_drvdata(ts->input, ts);
1068*48a2b783SJeffrey Lin 
1069*48a2b783SJeffrey Lin 	input_set_abs_params(ts->input, ABS_MT_POSITION_X,
1070*48a2b783SJeffrey Lin 			     0, le16_to_cpu(ts->info.x_max), 0, 0);
1071*48a2b783SJeffrey Lin 	input_set_abs_params(ts->input, ABS_MT_POSITION_Y,
1072*48a2b783SJeffrey Lin 			     0, le16_to_cpu(ts->info.y_max), 0, 0);
1073*48a2b783SJeffrey Lin 	input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->info.x_res);
1074*48a2b783SJeffrey Lin 	input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->info.y_res);
1075*48a2b783SJeffrey Lin 
1076*48a2b783SJeffrey Lin 	input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
1077*48a2b783SJeffrey Lin 	input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
1078*48a2b783SJeffrey Lin 
1079*48a2b783SJeffrey Lin 	error = input_mt_init_slots(ts->input, RM_MAX_TOUCH_NUM,
1080*48a2b783SJeffrey Lin 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
1081*48a2b783SJeffrey Lin 	if (error) {
1082*48a2b783SJeffrey Lin 		dev_err(&client->dev,
1083*48a2b783SJeffrey Lin 			"failed to initialize MT slots: %d\n", error);
1084*48a2b783SJeffrey Lin 		return error;
1085*48a2b783SJeffrey Lin 	}
1086*48a2b783SJeffrey Lin 
1087*48a2b783SJeffrey Lin 	error = input_register_device(ts->input);
1088*48a2b783SJeffrey Lin 	if (error) {
1089*48a2b783SJeffrey Lin 		dev_err(&client->dev,
1090*48a2b783SJeffrey Lin 			"unable to register input device: %d\n", error);
1091*48a2b783SJeffrey Lin 		return error;
1092*48a2b783SJeffrey Lin 	}
1093*48a2b783SJeffrey Lin 
1094*48a2b783SJeffrey Lin 	error = devm_request_threaded_irq(&client->dev, client->irq,
1095*48a2b783SJeffrey Lin 					  NULL, raydium_i2c_irq,
1096*48a2b783SJeffrey Lin 					  IRQF_ONESHOT, client->name, ts);
1097*48a2b783SJeffrey Lin 	if (error) {
1098*48a2b783SJeffrey Lin 		dev_err(&client->dev, "Failed to register interrupt\n");
1099*48a2b783SJeffrey Lin 		return error;
1100*48a2b783SJeffrey Lin 	}
1101*48a2b783SJeffrey Lin 
1102*48a2b783SJeffrey Lin 	error = sysfs_create_group(&client->dev.kobj,
1103*48a2b783SJeffrey Lin 				   &raydium_i2c_attribute_group);
1104*48a2b783SJeffrey Lin 	if (error) {
1105*48a2b783SJeffrey Lin 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
1106*48a2b783SJeffrey Lin 			error);
1107*48a2b783SJeffrey Lin 		return error;
1108*48a2b783SJeffrey Lin 	}
1109*48a2b783SJeffrey Lin 
1110*48a2b783SJeffrey Lin 	error = devm_add_action(&client->dev,
1111*48a2b783SJeffrey Lin 				raydium_i2c_remove_sysfs_group, ts);
1112*48a2b783SJeffrey Lin 	if (error) {
1113*48a2b783SJeffrey Lin 		raydium_i2c_remove_sysfs_group(ts);
1114*48a2b783SJeffrey Lin 		dev_err(&client->dev,
1115*48a2b783SJeffrey Lin 			"Failed to add sysfs cleanup action: %d\n", error);
1116*48a2b783SJeffrey Lin 		return error;
1117*48a2b783SJeffrey Lin 	}
1118*48a2b783SJeffrey Lin 
1119*48a2b783SJeffrey Lin 	return 0;
1120*48a2b783SJeffrey Lin }
1121*48a2b783SJeffrey Lin 
1122*48a2b783SJeffrey Lin static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
1123*48a2b783SJeffrey Lin {
1124*48a2b783SJeffrey Lin 	static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f };
1125*48a2b783SJeffrey Lin 	int error;
1126*48a2b783SJeffrey Lin 
1127*48a2b783SJeffrey Lin 	error = raydium_i2c_send(client, RM_CMD_ENTER_SLEEP,
1128*48a2b783SJeffrey Lin 				 sleep_cmd, sizeof(sleep_cmd));
1129*48a2b783SJeffrey Lin 	if (error)
1130*48a2b783SJeffrey Lin 		dev_err(&client->dev,
1131*48a2b783SJeffrey Lin 			"sleep command failed: %d\n", error);
1132*48a2b783SJeffrey Lin }
1133*48a2b783SJeffrey Lin 
1134*48a2b783SJeffrey Lin static int __maybe_unused raydium_i2c_suspend(struct device *dev)
1135*48a2b783SJeffrey Lin {
1136*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
1137*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
1138*48a2b783SJeffrey Lin 
1139*48a2b783SJeffrey Lin 	/* Sleep is not available in BLDR recovery mode */
1140*48a2b783SJeffrey Lin 	if (ts->boot_mode != RAYDIUM_TS_MAIN)
1141*48a2b783SJeffrey Lin 		return -ENOMEM;
1142*48a2b783SJeffrey Lin 
1143*48a2b783SJeffrey Lin 	disable_irq(client->irq);
1144*48a2b783SJeffrey Lin 
1145*48a2b783SJeffrey Lin 	if (device_may_wakeup(dev)) {
1146*48a2b783SJeffrey Lin 		raydium_enter_sleep(client);
1147*48a2b783SJeffrey Lin 
1148*48a2b783SJeffrey Lin 		ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0);
1149*48a2b783SJeffrey Lin 	} else {
1150*48a2b783SJeffrey Lin 		raydium_i2c_power_off(ts);
1151*48a2b783SJeffrey Lin 	}
1152*48a2b783SJeffrey Lin 
1153*48a2b783SJeffrey Lin 	return 0;
1154*48a2b783SJeffrey Lin }
1155*48a2b783SJeffrey Lin 
1156*48a2b783SJeffrey Lin static int __maybe_unused raydium_i2c_resume(struct device *dev)
1157*48a2b783SJeffrey Lin {
1158*48a2b783SJeffrey Lin 	struct i2c_client *client = to_i2c_client(dev);
1159*48a2b783SJeffrey Lin 	struct raydium_data *ts = i2c_get_clientdata(client);
1160*48a2b783SJeffrey Lin 
1161*48a2b783SJeffrey Lin 	if (device_may_wakeup(dev)) {
1162*48a2b783SJeffrey Lin 		if (ts->wake_irq_enabled)
1163*48a2b783SJeffrey Lin 			disable_irq_wake(client->irq);
1164*48a2b783SJeffrey Lin 		raydium_i2c_sw_reset(client);
1165*48a2b783SJeffrey Lin 	} else {
1166*48a2b783SJeffrey Lin 		raydium_i2c_power_on(ts);
1167*48a2b783SJeffrey Lin 		raydium_i2c_initialize(ts);
1168*48a2b783SJeffrey Lin 	}
1169*48a2b783SJeffrey Lin 
1170*48a2b783SJeffrey Lin 	enable_irq(client->irq);
1171*48a2b783SJeffrey Lin 
1172*48a2b783SJeffrey Lin 	return 0;
1173*48a2b783SJeffrey Lin }
1174*48a2b783SJeffrey Lin 
1175*48a2b783SJeffrey Lin static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
1176*48a2b783SJeffrey Lin 			 raydium_i2c_suspend, raydium_i2c_resume);
1177*48a2b783SJeffrey Lin 
1178*48a2b783SJeffrey Lin static const struct i2c_device_id raydium_i2c_id[] = {
1179*48a2b783SJeffrey Lin 	{ "raydium_i2c" , 0 },
1180*48a2b783SJeffrey Lin 	{ "rm32380", 0 },
1181*48a2b783SJeffrey Lin 	{ /* sentinel */ }
1182*48a2b783SJeffrey Lin };
1183*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(i2c, raydium_i2c_id);
1184*48a2b783SJeffrey Lin 
1185*48a2b783SJeffrey Lin #ifdef CONFIG_ACPI
1186*48a2b783SJeffrey Lin static const struct acpi_device_id raydium_acpi_id[] = {
1187*48a2b783SJeffrey Lin 	{ "RAYD0001", 0 },
1188*48a2b783SJeffrey Lin 	{ /* sentinel */ }
1189*48a2b783SJeffrey Lin };
1190*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(acpi, raydium_acpi_id);
1191*48a2b783SJeffrey Lin #endif
1192*48a2b783SJeffrey Lin 
1193*48a2b783SJeffrey Lin #ifdef CONFIG_OF
1194*48a2b783SJeffrey Lin static const struct of_device_id raydium_of_match[] = {
1195*48a2b783SJeffrey Lin 	{ .compatible = "raydium,rm32380", },
1196*48a2b783SJeffrey Lin 	{ /* sentinel */ }
1197*48a2b783SJeffrey Lin };
1198*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(of, raydium_of_match);
1199*48a2b783SJeffrey Lin #endif
1200*48a2b783SJeffrey Lin 
1201*48a2b783SJeffrey Lin static struct i2c_driver raydium_i2c_driver = {
1202*48a2b783SJeffrey Lin 	.probe = raydium_i2c_probe,
1203*48a2b783SJeffrey Lin 	.id_table = raydium_i2c_id,
1204*48a2b783SJeffrey Lin 	.driver = {
1205*48a2b783SJeffrey Lin 		.name = "raydium_ts",
1206*48a2b783SJeffrey Lin 		.pm = &raydium_i2c_pm_ops,
1207*48a2b783SJeffrey Lin 		.acpi_match_table = ACPI_PTR(raydium_acpi_id),
1208*48a2b783SJeffrey Lin 		.of_match_table = of_match_ptr(raydium_of_match),
1209*48a2b783SJeffrey Lin 	},
1210*48a2b783SJeffrey Lin };
1211*48a2b783SJeffrey Lin module_i2c_driver(raydium_i2c_driver);
1212*48a2b783SJeffrey Lin 
1213*48a2b783SJeffrey Lin MODULE_AUTHOR("Raydium");
1214*48a2b783SJeffrey Lin MODULE_DESCRIPTION("Raydium I2c Touchscreen driver");
1215*48a2b783SJeffrey Lin MODULE_LICENSE("GPL v2");
1216