xref: /openbmc/linux/drivers/input/touchscreen/ili210x.c (revision 70a7681db0c9266bd0a3fd6c90a5cfa20ac44995)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
271f8e38aSDmitry Torokhov #include <linux/delay.h>
371f8e38aSDmitry Torokhov #include <linux/gpio/consumer.h>
45c6a7a62SOlivier Sobrie #include <linux/i2c.h>
55c6a7a62SOlivier Sobrie #include <linux/input.h>
65c6a7a62SOlivier Sobrie #include <linux/input/mt.h>
7f67cc3e9SMarek Vasut #include <linux/input/touchscreen.h>
871f8e38aSDmitry Torokhov #include <linux/interrupt.h>
971f8e38aSDmitry Torokhov #include <linux/module.h>
1049588917SMarek Vasut #include <linux/of_device.h>
11b32fbeaeSSven Van Asbroeck #include <linux/sizes.h>
1271f8e38aSDmitry Torokhov #include <linux/slab.h>
13e3559442SMarek Vasut #include <asm/unaligned.h>
145c6a7a62SOlivier Sobrie 
1571f8e38aSDmitry Torokhov #define ILI2XXX_POLL_PERIOD	20
165c6a7a62SOlivier Sobrie 
17ef536abdSDmitry Torokhov #define ILI210X_DATA_SIZE	64
18ef536abdSDmitry Torokhov #define ILI211X_DATA_SIZE	43
19ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE1	31
20ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE2	20
21ef536abdSDmitry Torokhov 
225c6a7a62SOlivier Sobrie /* Touchscreen commands */
235c6a7a62SOlivier Sobrie #define REG_TOUCHDATA		0x10
245c6a7a62SOlivier Sobrie #define REG_PANEL_INFO		0x20
25*70a7681dSMarek Vasut #define REG_FIRMWARE_VERSION	0x40
26*70a7681dSMarek Vasut #define REG_PROTOCOL_VERSION	0x42
27*70a7681dSMarek Vasut #define REG_KERNEL_VERSION	0x61
28*70a7681dSMarek Vasut #define REG_GET_MODE		0xc0
29*70a7681dSMarek Vasut #define REG_GET_MODE_AP		0x5a
30*70a7681dSMarek Vasut #define REG_GET_MODE_BL		0x55
315c6a7a62SOlivier Sobrie #define REG_CALIBRATE		0xcc
325c6a7a62SOlivier Sobrie 
33ef536abdSDmitry Torokhov struct ili2xxx_chip {
34ef536abdSDmitry Torokhov 	int (*read_reg)(struct i2c_client *client, u8 reg,
35ef536abdSDmitry Torokhov 			void *buf, size_t len);
36ef536abdSDmitry Torokhov 	int (*get_touch_data)(struct i2c_client *client, u8 *data);
37ef536abdSDmitry Torokhov 	bool (*parse_touch_data)(const u8 *data, unsigned int finger,
3860159e9eSMarek Vasut 				 unsigned int *x, unsigned int *y,
3960159e9eSMarek Vasut 				 unsigned int *z);
40ef536abdSDmitry Torokhov 	bool (*continue_polling)(const u8 *data, bool touch);
41ef536abdSDmitry Torokhov 	unsigned int max_touches;
42b32fbeaeSSven Van Asbroeck 	unsigned int resolution;
43cc12ba18SSven Van Asbroeck 	bool has_calibrate_reg;
44235300edSMarek Vasut 	bool has_firmware_proto;
4560159e9eSMarek Vasut 	bool has_pressure_reg;
4649588917SMarek Vasut };
4749588917SMarek Vasut 
485c6a7a62SOlivier Sobrie struct ili210x {
495c6a7a62SOlivier Sobrie 	struct i2c_client *client;
505c6a7a62SOlivier Sobrie 	struct input_dev *input;
51201f3c80SMarek Vasut 	struct gpio_desc *reset_gpio;
52f67cc3e9SMarek Vasut 	struct touchscreen_properties prop;
53ef536abdSDmitry Torokhov 	const struct ili2xxx_chip *chip;
54*70a7681dSMarek Vasut 	u8 version_firmware[8];
55*70a7681dSMarek Vasut 	u8 version_kernel[5];
56*70a7681dSMarek Vasut 	u8 version_proto[2];
57*70a7681dSMarek Vasut 	u8 ic_mode[2];
5871f8e38aSDmitry Torokhov 	bool stop;
595c6a7a62SOlivier Sobrie };
605c6a7a62SOlivier Sobrie 
61ef536abdSDmitry Torokhov static int ili210x_read_reg(struct i2c_client *client,
62ef536abdSDmitry Torokhov 			    u8 reg, void *buf, size_t len)
635c6a7a62SOlivier Sobrie {
64ef536abdSDmitry Torokhov 	struct i2c_msg msg[] = {
655c6a7a62SOlivier Sobrie 		{
665c6a7a62SOlivier Sobrie 			.addr	= client->addr,
675c6a7a62SOlivier Sobrie 			.flags	= 0,
685c6a7a62SOlivier Sobrie 			.len	= 1,
695c6a7a62SOlivier Sobrie 			.buf	= &reg,
705c6a7a62SOlivier Sobrie 		},
715c6a7a62SOlivier Sobrie 		{
725c6a7a62SOlivier Sobrie 			.addr	= client->addr,
735c6a7a62SOlivier Sobrie 			.flags	= I2C_M_RD,
745c6a7a62SOlivier Sobrie 			.len	= len,
755c6a7a62SOlivier Sobrie 			.buf	= buf,
765c6a7a62SOlivier Sobrie 		}
775c6a7a62SOlivier Sobrie 	};
78ef536abdSDmitry Torokhov 	int error, ret;
795c6a7a62SOlivier Sobrie 
80ef536abdSDmitry Torokhov 	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
81ef536abdSDmitry Torokhov 	if (ret != ARRAY_SIZE(msg)) {
82ef536abdSDmitry Torokhov 		error = ret < 0 ? ret : -EIO;
83ef536abdSDmitry Torokhov 		dev_err(&client->dev, "%s failed: %d\n", __func__, error);
84ef536abdSDmitry Torokhov 		return error;
8549588917SMarek Vasut 	}
8649588917SMarek Vasut 
8749588917SMarek Vasut 	return 0;
8849588917SMarek Vasut }
8949588917SMarek Vasut 
90ef536abdSDmitry Torokhov static int ili210x_read_touch_data(struct i2c_client *client, u8 *data)
9149588917SMarek Vasut {
92ef536abdSDmitry Torokhov 	return ili210x_read_reg(client, REG_TOUCHDATA,
93ef536abdSDmitry Torokhov 				data, ILI210X_DATA_SIZE);
9449588917SMarek Vasut }
955c6a7a62SOlivier Sobrie 
96ef536abdSDmitry Torokhov static bool ili210x_touchdata_to_coords(const u8 *touchdata,
97e3559442SMarek Vasut 					unsigned int finger,
9860159e9eSMarek Vasut 					unsigned int *x, unsigned int *y,
9960159e9eSMarek Vasut 					unsigned int *z)
1005c6a7a62SOlivier Sobrie {
101ac05a8a9SHansem Ro 	if (!(touchdata[0] & BIT(finger)))
102e3559442SMarek Vasut 		return false;
103e3559442SMarek Vasut 
104e3559442SMarek Vasut 	*x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
105e3559442SMarek Vasut 	*y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
106e3559442SMarek Vasut 
107e3559442SMarek Vasut 	return true;
108e3559442SMarek Vasut }
109e3559442SMarek Vasut 
110ef536abdSDmitry Torokhov static bool ili210x_check_continue_polling(const u8 *data, bool touch)
111ef536abdSDmitry Torokhov {
112ef536abdSDmitry Torokhov 	return data[0] & 0xf3;
113ef536abdSDmitry Torokhov }
114ef536abdSDmitry Torokhov 
115ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili210x_chip = {
116ef536abdSDmitry Torokhov 	.read_reg		= ili210x_read_reg,
117ef536abdSDmitry Torokhov 	.get_touch_data		= ili210x_read_touch_data,
118ef536abdSDmitry Torokhov 	.parse_touch_data	= ili210x_touchdata_to_coords,
119ef536abdSDmitry Torokhov 	.continue_polling	= ili210x_check_continue_polling,
120ef536abdSDmitry Torokhov 	.max_touches		= 2,
121cc12ba18SSven Van Asbroeck 	.has_calibrate_reg	= true,
122ef536abdSDmitry Torokhov };
123ef536abdSDmitry Torokhov 
124ef536abdSDmitry Torokhov static int ili211x_read_touch_data(struct i2c_client *client, u8 *data)
125ef536abdSDmitry Torokhov {
126ef536abdSDmitry Torokhov 	s16 sum = 0;
127ef536abdSDmitry Torokhov 	int error;
128ef536abdSDmitry Torokhov 	int ret;
129ef536abdSDmitry Torokhov 	int i;
130ef536abdSDmitry Torokhov 
131ef536abdSDmitry Torokhov 	ret = i2c_master_recv(client, data, ILI211X_DATA_SIZE);
132ef536abdSDmitry Torokhov 	if (ret != ILI211X_DATA_SIZE) {
133ef536abdSDmitry Torokhov 		error = ret < 0 ? ret : -EIO;
134ef536abdSDmitry Torokhov 		dev_err(&client->dev, "%s failed: %d\n", __func__, error);
135ef536abdSDmitry Torokhov 		return error;
136ef536abdSDmitry Torokhov 	}
137ef536abdSDmitry Torokhov 
138ef536abdSDmitry Torokhov 	/* This chip uses custom checksum at the end of data */
139ef536abdSDmitry Torokhov 	for (i = 0; i < ILI211X_DATA_SIZE - 1; i++)
140ef536abdSDmitry Torokhov 		sum = (sum + data[i]) & 0xff;
141ef536abdSDmitry Torokhov 
142ef536abdSDmitry Torokhov 	if ((-sum & 0xff) != data[ILI211X_DATA_SIZE - 1]) {
143ef536abdSDmitry Torokhov 		dev_err(&client->dev,
144ef536abdSDmitry Torokhov 			"CRC error (crc=0x%02x expected=0x%02x)\n",
145ef536abdSDmitry Torokhov 			sum, data[ILI211X_DATA_SIZE - 1]);
146ef536abdSDmitry Torokhov 		return -EIO;
147ef536abdSDmitry Torokhov 	}
148ef536abdSDmitry Torokhov 
149ef536abdSDmitry Torokhov 	return 0;
150ef536abdSDmitry Torokhov }
151ef536abdSDmitry Torokhov 
152ef536abdSDmitry Torokhov static bool ili211x_touchdata_to_coords(const u8 *touchdata,
153eb91ecc9SMarek Vasut 					unsigned int finger,
15460159e9eSMarek Vasut 					unsigned int *x, unsigned int *y,
15560159e9eSMarek Vasut 					unsigned int *z)
156eb91ecc9SMarek Vasut {
157eb91ecc9SMarek Vasut 	u32 data;
158eb91ecc9SMarek Vasut 
159eb91ecc9SMarek Vasut 	data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0);
160eb91ecc9SMarek Vasut 	if (data == 0xffffffff)	/* Finger up */
161eb91ecc9SMarek Vasut 		return false;
162eb91ecc9SMarek Vasut 
163eb91ecc9SMarek Vasut 	*x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) |
164eb91ecc9SMarek Vasut 	     touchdata[1 + (finger * 4) + 1];
165eb91ecc9SMarek Vasut 	*y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) |
166eb91ecc9SMarek Vasut 	     touchdata[1 + (finger * 4) + 2];
167eb91ecc9SMarek Vasut 
168eb91ecc9SMarek Vasut 	return true;
169eb91ecc9SMarek Vasut }
170eb91ecc9SMarek Vasut 
171ef536abdSDmitry Torokhov static bool ili211x_decline_polling(const u8 *data, bool touch)
172ef536abdSDmitry Torokhov {
173ef536abdSDmitry Torokhov 	return false;
174ef536abdSDmitry Torokhov }
175ef536abdSDmitry Torokhov 
176ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili211x_chip = {
177ef536abdSDmitry Torokhov 	.read_reg		= ili210x_read_reg,
178ef536abdSDmitry Torokhov 	.get_touch_data		= ili211x_read_touch_data,
179ef536abdSDmitry Torokhov 	.parse_touch_data	= ili211x_touchdata_to_coords,
180ef536abdSDmitry Torokhov 	.continue_polling	= ili211x_decline_polling,
181ef536abdSDmitry Torokhov 	.max_touches		= 10,
182b32fbeaeSSven Van Asbroeck 	.resolution		= 2048,
183ef536abdSDmitry Torokhov };
184ef536abdSDmitry Torokhov 
185d0c5e7d4SLuca Weiss static bool ili212x_touchdata_to_coords(const u8 *touchdata,
186d0c5e7d4SLuca Weiss 					unsigned int finger,
18760159e9eSMarek Vasut 					unsigned int *x, unsigned int *y,
18860159e9eSMarek Vasut 					unsigned int *z)
189d0c5e7d4SLuca Weiss {
190d0c5e7d4SLuca Weiss 	u16 val;
191d0c5e7d4SLuca Weiss 
192d0c5e7d4SLuca Weiss 	val = get_unaligned_be16(touchdata + 3 + (finger * 5) + 0);
193d0c5e7d4SLuca Weiss 	if (!(val & BIT(15)))	/* Touch indication */
194d0c5e7d4SLuca Weiss 		return false;
195d0c5e7d4SLuca Weiss 
196d0c5e7d4SLuca Weiss 	*x = val & 0x3fff;
197d0c5e7d4SLuca Weiss 	*y = get_unaligned_be16(touchdata + 3 + (finger * 5) + 2);
198d0c5e7d4SLuca Weiss 
199d0c5e7d4SLuca Weiss 	return true;
200d0c5e7d4SLuca Weiss }
201d0c5e7d4SLuca Weiss 
202d0c5e7d4SLuca Weiss static bool ili212x_check_continue_polling(const u8 *data, bool touch)
203d0c5e7d4SLuca Weiss {
204d0c5e7d4SLuca Weiss 	return touch;
205d0c5e7d4SLuca Weiss }
206d0c5e7d4SLuca Weiss 
207d0c5e7d4SLuca Weiss static const struct ili2xxx_chip ili212x_chip = {
208d0c5e7d4SLuca Weiss 	.read_reg		= ili210x_read_reg,
209d0c5e7d4SLuca Weiss 	.get_touch_data		= ili210x_read_touch_data,
210d0c5e7d4SLuca Weiss 	.parse_touch_data	= ili212x_touchdata_to_coords,
211d0c5e7d4SLuca Weiss 	.continue_polling	= ili212x_check_continue_polling,
212d0c5e7d4SLuca Weiss 	.max_touches		= 10,
213d0c5e7d4SLuca Weiss 	.has_calibrate_reg	= true,
214d0c5e7d4SLuca Weiss };
215d0c5e7d4SLuca Weiss 
216ef536abdSDmitry Torokhov static int ili251x_read_reg(struct i2c_client *client,
217ef536abdSDmitry Torokhov 			    u8 reg, void *buf, size_t len)
218ef536abdSDmitry Torokhov {
219ef536abdSDmitry Torokhov 	int error;
220ef536abdSDmitry Torokhov 	int ret;
221ef536abdSDmitry Torokhov 
222ef536abdSDmitry Torokhov 	ret = i2c_master_send(client, &reg, 1);
223ef536abdSDmitry Torokhov 	if (ret == 1) {
224ef536abdSDmitry Torokhov 		usleep_range(5000, 5500);
225ef536abdSDmitry Torokhov 
226ef536abdSDmitry Torokhov 		ret = i2c_master_recv(client, buf, len);
227ef536abdSDmitry Torokhov 		if (ret == len)
228ef536abdSDmitry Torokhov 			return 0;
229ef536abdSDmitry Torokhov 	}
230ef536abdSDmitry Torokhov 
231ef536abdSDmitry Torokhov 	error = ret < 0 ? ret : -EIO;
232ef536abdSDmitry Torokhov 	dev_err(&client->dev, "%s failed: %d\n", __func__, error);
233ef536abdSDmitry Torokhov 	return ret;
234ef536abdSDmitry Torokhov }
235ef536abdSDmitry Torokhov 
236ef536abdSDmitry Torokhov static int ili251x_read_touch_data(struct i2c_client *client, u8 *data)
237ef536abdSDmitry Torokhov {
238ef536abdSDmitry Torokhov 	int error;
239ef536abdSDmitry Torokhov 
240ef536abdSDmitry Torokhov 	error = ili251x_read_reg(client, REG_TOUCHDATA,
241ef536abdSDmitry Torokhov 				 data, ILI251X_DATA_SIZE1);
242ef536abdSDmitry Torokhov 	if (!error && data[0] == 2) {
243ef536abdSDmitry Torokhov 		error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1,
244ef536abdSDmitry Torokhov 					ILI251X_DATA_SIZE2);
245ef536abdSDmitry Torokhov 		if (error >= 0 && error != ILI251X_DATA_SIZE2)
246ef536abdSDmitry Torokhov 			error = -EIO;
247ef536abdSDmitry Torokhov 	}
248ef536abdSDmitry Torokhov 
249ef536abdSDmitry Torokhov 	return error;
250ef536abdSDmitry Torokhov }
251ef536abdSDmitry Torokhov 
252ef536abdSDmitry Torokhov static bool ili251x_touchdata_to_coords(const u8 *touchdata,
25349588917SMarek Vasut 					unsigned int finger,
25460159e9eSMarek Vasut 					unsigned int *x, unsigned int *y,
25560159e9eSMarek Vasut 					unsigned int *z)
25649588917SMarek Vasut {
257ef536abdSDmitry Torokhov 	u16 val;
258ef536abdSDmitry Torokhov 
259ef536abdSDmitry Torokhov 	val = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
260ef536abdSDmitry Torokhov 	if (!(val & BIT(15)))	/* Touch indication */
26149588917SMarek Vasut 		return false;
26249588917SMarek Vasut 
263ef536abdSDmitry Torokhov 	*x = val & 0x3fff;
26449588917SMarek Vasut 	*y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
26560159e9eSMarek Vasut 	*z = touchdata[1 + (finger * 5) + 4];
26649588917SMarek Vasut 
26749588917SMarek Vasut 	return true;
26849588917SMarek Vasut }
26949588917SMarek Vasut 
270ef536abdSDmitry Torokhov static bool ili251x_check_continue_polling(const u8 *data, bool touch)
271ef536abdSDmitry Torokhov {
272ef536abdSDmitry Torokhov 	return touch;
273ef536abdSDmitry Torokhov }
274ef536abdSDmitry Torokhov 
275ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili251x_chip = {
276ef536abdSDmitry Torokhov 	.read_reg		= ili251x_read_reg,
277ef536abdSDmitry Torokhov 	.get_touch_data		= ili251x_read_touch_data,
278ef536abdSDmitry Torokhov 	.parse_touch_data	= ili251x_touchdata_to_coords,
279ef536abdSDmitry Torokhov 	.continue_polling	= ili251x_check_continue_polling,
280ef536abdSDmitry Torokhov 	.max_touches		= 10,
281cc12ba18SSven Van Asbroeck 	.has_calibrate_reg	= true,
282235300edSMarek Vasut 	.has_firmware_proto	= true,
28360159e9eSMarek Vasut 	.has_pressure_reg	= true,
284ef536abdSDmitry Torokhov };
285ef536abdSDmitry Torokhov 
286e3559442SMarek Vasut static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
287e3559442SMarek Vasut {
288e3559442SMarek Vasut 	struct input_dev *input = priv->input;
2895c6a7a62SOlivier Sobrie 	int i;
290ef536abdSDmitry Torokhov 	bool contact = false, touch;
29160159e9eSMarek Vasut 	unsigned int x = 0, y = 0, z = 0;
2925c6a7a62SOlivier Sobrie 
293ef536abdSDmitry Torokhov 	for (i = 0; i < priv->chip->max_touches; i++) {
29460159e9eSMarek Vasut 		touch = priv->chip->parse_touch_data(touchdata, i, &x, &y, &z);
29549588917SMarek Vasut 
296f67cc3e9SMarek Vasut 		input_mt_slot(input, i);
297ef536abdSDmitry Torokhov 		if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) {
298ef536abdSDmitry Torokhov 			touchscreen_report_pos(input, &priv->prop, x, y, true);
29960159e9eSMarek Vasut 			if (priv->chip->has_pressure_reg)
30060159e9eSMarek Vasut 				input_report_abs(input, ABS_MT_PRESSURE, z);
301ef536abdSDmitry Torokhov 			contact = true;
302ef536abdSDmitry Torokhov 		}
3035c6a7a62SOlivier Sobrie 	}
3045c6a7a62SOlivier Sobrie 
3055c6a7a62SOlivier Sobrie 	input_mt_report_pointer_emulation(input, false);
3065c6a7a62SOlivier Sobrie 	input_sync(input);
307e3559442SMarek Vasut 
30849588917SMarek Vasut 	return contact;
3095c6a7a62SOlivier Sobrie }
3105c6a7a62SOlivier Sobrie 
31171f8e38aSDmitry Torokhov static irqreturn_t ili210x_irq(int irq, void *irq_data)
3125c6a7a62SOlivier Sobrie {
31371f8e38aSDmitry Torokhov 	struct ili210x *priv = irq_data;
3145c6a7a62SOlivier Sobrie 	struct i2c_client *client = priv->client;
315ef536abdSDmitry Torokhov 	const struct ili2xxx_chip *chip = priv->chip;
316ef536abdSDmitry Torokhov 	u8 touchdata[ILI210X_DATA_SIZE] = { 0 };
317ef536abdSDmitry Torokhov 	bool keep_polling;
318e3559442SMarek Vasut 	bool touch;
31971f8e38aSDmitry Torokhov 	int error;
3205c6a7a62SOlivier Sobrie 
32171f8e38aSDmitry Torokhov 	do {
322ef536abdSDmitry Torokhov 		error = chip->get_touch_data(client, touchdata);
3235c6a7a62SOlivier Sobrie 		if (error) {
3245c6a7a62SOlivier Sobrie 			dev_err(&client->dev,
325ef536abdSDmitry Torokhov 				"Unable to get touch data: %d\n", error);
32671f8e38aSDmitry Torokhov 			break;
3275c6a7a62SOlivier Sobrie 		}
3285c6a7a62SOlivier Sobrie 
329e3559442SMarek Vasut 		touch = ili210x_report_events(priv, touchdata);
330ef536abdSDmitry Torokhov 		keep_polling = chip->continue_polling(touchdata, touch);
331ef536abdSDmitry Torokhov 		if (keep_polling)
33271f8e38aSDmitry Torokhov 			msleep(ILI2XXX_POLL_PERIOD);
333ef536abdSDmitry Torokhov 	} while (!priv->stop && keep_polling);
3345c6a7a62SOlivier Sobrie 
3355c6a7a62SOlivier Sobrie 	return IRQ_HANDLED;
3365c6a7a62SOlivier Sobrie }
3375c6a7a62SOlivier Sobrie 
338235300edSMarek Vasut static int ili251x_firmware_update_resolution(struct device *dev)
339235300edSMarek Vasut {
340235300edSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
341235300edSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
342235300edSMarek Vasut 	u16 resx, resy;
343235300edSMarek Vasut 	u8 rs[10];
344235300edSMarek Vasut 	int error;
345235300edSMarek Vasut 
346235300edSMarek Vasut 	/* The firmware update blob might have changed the resolution. */
347235300edSMarek Vasut 	error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs));
348235300edSMarek Vasut 	if (error)
349235300edSMarek Vasut 		return error;
350235300edSMarek Vasut 
351235300edSMarek Vasut 	resx = le16_to_cpup((__le16 *)rs);
352235300edSMarek Vasut 	resy = le16_to_cpup((__le16 *)(rs + 2));
353235300edSMarek Vasut 
354235300edSMarek Vasut 	/* The value reported by the firmware is invalid. */
355235300edSMarek Vasut 	if (!resx || resx == 0xffff || !resy || resy == 0xffff)
356235300edSMarek Vasut 		return -EINVAL;
357235300edSMarek Vasut 
358235300edSMarek Vasut 	input_abs_set_max(priv->input, ABS_X, resx - 1);
359235300edSMarek Vasut 	input_abs_set_max(priv->input, ABS_Y, resy - 1);
360235300edSMarek Vasut 	input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1);
361235300edSMarek Vasut 	input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1);
362235300edSMarek Vasut 
363235300edSMarek Vasut 	return 0;
364235300edSMarek Vasut }
365235300edSMarek Vasut 
366*70a7681dSMarek Vasut static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
367*70a7681dSMarek Vasut {
368*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
369*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
370*70a7681dSMarek Vasut 	int error;
371*70a7681dSMarek Vasut 	u8 fw[8];
372*70a7681dSMarek Vasut 
373*70a7681dSMarek Vasut 	/* Get firmware version */
374*70a7681dSMarek Vasut 	error = priv->chip->read_reg(client, REG_FIRMWARE_VERSION,
375*70a7681dSMarek Vasut 				     &fw, sizeof(fw));
376*70a7681dSMarek Vasut 	if (!error)
377*70a7681dSMarek Vasut 		memcpy(priv->version_firmware, fw, sizeof(fw));
378*70a7681dSMarek Vasut 
379*70a7681dSMarek Vasut 	return error;
380*70a7681dSMarek Vasut }
381*70a7681dSMarek Vasut 
382*70a7681dSMarek Vasut static ssize_t ili251x_firmware_update_kernel_version(struct device *dev)
383*70a7681dSMarek Vasut {
384*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
385*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
386*70a7681dSMarek Vasut 	int error;
387*70a7681dSMarek Vasut 	u8 kv[5];
388*70a7681dSMarek Vasut 
389*70a7681dSMarek Vasut 	/* Get kernel version */
390*70a7681dSMarek Vasut 	error = priv->chip->read_reg(client, REG_KERNEL_VERSION,
391*70a7681dSMarek Vasut 				     &kv, sizeof(kv));
392*70a7681dSMarek Vasut 	if (!error)
393*70a7681dSMarek Vasut 		memcpy(priv->version_kernel, kv, sizeof(kv));
394*70a7681dSMarek Vasut 
395*70a7681dSMarek Vasut 	return error;
396*70a7681dSMarek Vasut }
397*70a7681dSMarek Vasut 
398*70a7681dSMarek Vasut static ssize_t ili251x_firmware_update_protocol_version(struct device *dev)
399*70a7681dSMarek Vasut {
400*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
401*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
402*70a7681dSMarek Vasut 	int error;
403*70a7681dSMarek Vasut 	u8 pv[2];
404*70a7681dSMarek Vasut 
405*70a7681dSMarek Vasut 	/* Get protocol version */
406*70a7681dSMarek Vasut 	error = priv->chip->read_reg(client, REG_PROTOCOL_VERSION,
407*70a7681dSMarek Vasut 				     &pv, sizeof(pv));
408*70a7681dSMarek Vasut 	if (!error)
409*70a7681dSMarek Vasut 		memcpy(priv->version_proto, pv, sizeof(pv));
410*70a7681dSMarek Vasut 
411*70a7681dSMarek Vasut 	return error;
412*70a7681dSMarek Vasut }
413*70a7681dSMarek Vasut 
414*70a7681dSMarek Vasut static ssize_t ili251x_firmware_update_ic_mode(struct device *dev)
415*70a7681dSMarek Vasut {
416*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
417*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
418*70a7681dSMarek Vasut 	int error;
419*70a7681dSMarek Vasut 	u8 md[2];
420*70a7681dSMarek Vasut 
421*70a7681dSMarek Vasut 	/* Get chip boot mode */
422*70a7681dSMarek Vasut 	error = priv->chip->read_reg(client, REG_GET_MODE, &md, sizeof(md));
423*70a7681dSMarek Vasut 	if (!error)
424*70a7681dSMarek Vasut 		memcpy(priv->ic_mode, md, sizeof(md));
425*70a7681dSMarek Vasut 
426*70a7681dSMarek Vasut 	return error;
427*70a7681dSMarek Vasut }
428*70a7681dSMarek Vasut 
429235300edSMarek Vasut static int ili251x_firmware_update_cached_state(struct device *dev)
430235300edSMarek Vasut {
431235300edSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
432235300edSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
433235300edSMarek Vasut 	int error;
434235300edSMarek Vasut 
435235300edSMarek Vasut 	if (!priv->chip->has_firmware_proto)
436235300edSMarek Vasut 		return 0;
437235300edSMarek Vasut 
438235300edSMarek Vasut 	/* Wait for firmware to boot and stabilize itself. */
439235300edSMarek Vasut 	msleep(200);
440235300edSMarek Vasut 
441235300edSMarek Vasut 	/* Firmware does report valid information. */
442235300edSMarek Vasut 	error = ili251x_firmware_update_resolution(dev);
443235300edSMarek Vasut 	if (error)
444235300edSMarek Vasut 		return error;
445235300edSMarek Vasut 
446*70a7681dSMarek Vasut 	error = ili251x_firmware_update_firmware_version(dev);
447*70a7681dSMarek Vasut 	if (error)
448*70a7681dSMarek Vasut 		return error;
449*70a7681dSMarek Vasut 
450*70a7681dSMarek Vasut 	error = ili251x_firmware_update_kernel_version(dev);
451*70a7681dSMarek Vasut 	if (error)
452*70a7681dSMarek Vasut 		return error;
453*70a7681dSMarek Vasut 
454*70a7681dSMarek Vasut 	error = ili251x_firmware_update_protocol_version(dev);
455*70a7681dSMarek Vasut 	if (error)
456*70a7681dSMarek Vasut 		return error;
457*70a7681dSMarek Vasut 
458*70a7681dSMarek Vasut 	error = ili251x_firmware_update_ic_mode(dev);
459*70a7681dSMarek Vasut 	if (error)
460*70a7681dSMarek Vasut 		return error;
461*70a7681dSMarek Vasut 
462235300edSMarek Vasut 	return 0;
463235300edSMarek Vasut }
464235300edSMarek Vasut 
465*70a7681dSMarek Vasut static ssize_t ili251x_firmware_version_show(struct device *dev,
466*70a7681dSMarek Vasut 					     struct device_attribute *attr,
467*70a7681dSMarek Vasut 					     char *buf)
468*70a7681dSMarek Vasut {
469*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
470*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
471*70a7681dSMarek Vasut 	u8 *fw = priv->version_firmware;
472*70a7681dSMarek Vasut 
473*70a7681dSMarek Vasut 	return sysfs_emit(buf, "%02x%02x.%02x%02x.%02x%02x.%02x%02x\n",
474*70a7681dSMarek Vasut 			  fw[0], fw[1], fw[2], fw[3],
475*70a7681dSMarek Vasut 			  fw[4], fw[5], fw[6], fw[7]);
476*70a7681dSMarek Vasut }
477*70a7681dSMarek Vasut static DEVICE_ATTR(firmware_version, 0444, ili251x_firmware_version_show, NULL);
478*70a7681dSMarek Vasut 
479*70a7681dSMarek Vasut static ssize_t ili251x_kernel_version_show(struct device *dev,
480*70a7681dSMarek Vasut 					   struct device_attribute *attr,
481*70a7681dSMarek Vasut 					   char *buf)
482*70a7681dSMarek Vasut {
483*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
484*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
485*70a7681dSMarek Vasut 	u8 *kv = priv->version_kernel;
486*70a7681dSMarek Vasut 
487*70a7681dSMarek Vasut 	return sysfs_emit(buf, "%02x.%02x.%02x.%02x.%02x\n",
488*70a7681dSMarek Vasut 			  kv[0], kv[1], kv[2], kv[3], kv[4]);
489*70a7681dSMarek Vasut }
490*70a7681dSMarek Vasut static DEVICE_ATTR(kernel_version, 0444, ili251x_kernel_version_show, NULL);
491*70a7681dSMarek Vasut 
492*70a7681dSMarek Vasut static ssize_t ili251x_protocol_version_show(struct device *dev,
493*70a7681dSMarek Vasut 					     struct device_attribute *attr,
494*70a7681dSMarek Vasut 					     char *buf)
495*70a7681dSMarek Vasut {
496*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
497*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
498*70a7681dSMarek Vasut 	u8 *pv = priv->version_proto;
499*70a7681dSMarek Vasut 
500*70a7681dSMarek Vasut 	return sysfs_emit(buf, "%02x.%02x\n", pv[0], pv[1]);
501*70a7681dSMarek Vasut }
502*70a7681dSMarek Vasut static DEVICE_ATTR(protocol_version, 0444, ili251x_protocol_version_show, NULL);
503*70a7681dSMarek Vasut 
504*70a7681dSMarek Vasut static ssize_t ili251x_mode_show(struct device *dev,
505*70a7681dSMarek Vasut 				 struct device_attribute *attr, char *buf)
506*70a7681dSMarek Vasut {
507*70a7681dSMarek Vasut 	struct i2c_client *client = to_i2c_client(dev);
508*70a7681dSMarek Vasut 	struct ili210x *priv = i2c_get_clientdata(client);
509*70a7681dSMarek Vasut 	u8 *md = priv->ic_mode;
510*70a7681dSMarek Vasut 	char *mode = "AP";
511*70a7681dSMarek Vasut 
512*70a7681dSMarek Vasut 	if (md[0] == REG_GET_MODE_AP)		/* Application Mode */
513*70a7681dSMarek Vasut 		mode = "AP";
514*70a7681dSMarek Vasut 	else if (md[0] == REG_GET_MODE_BL)	/* BootLoader Mode */
515*70a7681dSMarek Vasut 		mode = "BL";
516*70a7681dSMarek Vasut 	else					/* Unknown Mode */
517*70a7681dSMarek Vasut 		mode = "??";
518*70a7681dSMarek Vasut 
519*70a7681dSMarek Vasut 	return sysfs_emit(buf, "%02x.%02x:%s\n", md[0], md[1], mode);
520*70a7681dSMarek Vasut }
521*70a7681dSMarek Vasut static DEVICE_ATTR(mode, 0444, ili251x_mode_show, NULL);
522*70a7681dSMarek Vasut 
5235c6a7a62SOlivier Sobrie static ssize_t ili210x_calibrate(struct device *dev,
5245c6a7a62SOlivier Sobrie 				 struct device_attribute *attr,
5255c6a7a62SOlivier Sobrie 				 const char *buf, size_t count)
5265c6a7a62SOlivier Sobrie {
5275c6a7a62SOlivier Sobrie 	struct i2c_client *client = to_i2c_client(dev);
5285c6a7a62SOlivier Sobrie 	struct ili210x *priv = i2c_get_clientdata(client);
5295c6a7a62SOlivier Sobrie 	unsigned long calibrate;
5305c6a7a62SOlivier Sobrie 	int rc;
5315c6a7a62SOlivier Sobrie 	u8 cmd = REG_CALIBRATE;
5325c6a7a62SOlivier Sobrie 
5335c6a7a62SOlivier Sobrie 	if (kstrtoul(buf, 10, &calibrate))
5345c6a7a62SOlivier Sobrie 		return -EINVAL;
5355c6a7a62SOlivier Sobrie 
5365c6a7a62SOlivier Sobrie 	if (calibrate > 1)
5375c6a7a62SOlivier Sobrie 		return -EINVAL;
5385c6a7a62SOlivier Sobrie 
5395c6a7a62SOlivier Sobrie 	if (calibrate) {
5405c6a7a62SOlivier Sobrie 		rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
5415c6a7a62SOlivier Sobrie 		if (rc != sizeof(cmd))
5425c6a7a62SOlivier Sobrie 			return -EIO;
5435c6a7a62SOlivier Sobrie 	}
5445c6a7a62SOlivier Sobrie 
5455c6a7a62SOlivier Sobrie 	return count;
5465c6a7a62SOlivier Sobrie }
547b27c0d0cSDmitry Torokhov static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
5485c6a7a62SOlivier Sobrie 
5495c6a7a62SOlivier Sobrie static struct attribute *ili210x_attributes[] = {
5505c6a7a62SOlivier Sobrie 	&dev_attr_calibrate.attr,
551*70a7681dSMarek Vasut 	&dev_attr_firmware_version.attr,
552*70a7681dSMarek Vasut 	&dev_attr_kernel_version.attr,
553*70a7681dSMarek Vasut 	&dev_attr_protocol_version.attr,
554*70a7681dSMarek Vasut 	&dev_attr_mode.attr,
5555c6a7a62SOlivier Sobrie 	NULL,
5565c6a7a62SOlivier Sobrie };
5575c6a7a62SOlivier Sobrie 
558*70a7681dSMarek Vasut static umode_t ili210x_attributes_visible(struct kobject *kobj,
559cc12ba18SSven Van Asbroeck 					  struct attribute *attr, int index)
560cc12ba18SSven Van Asbroeck {
561cc12ba18SSven Van Asbroeck 	struct device *dev = kobj_to_dev(kobj);
562cc12ba18SSven Van Asbroeck 	struct i2c_client *client = to_i2c_client(dev);
563cc12ba18SSven Van Asbroeck 	struct ili210x *priv = i2c_get_clientdata(client);
564cc12ba18SSven Van Asbroeck 
565*70a7681dSMarek Vasut 	/* Calibrate is present on all ILI2xxx which have calibrate register */
566*70a7681dSMarek Vasut 	if (attr == &dev_attr_calibrate.attr)
567fbd1ec00SLuca Weiss 		return priv->chip->has_calibrate_reg ? attr->mode : 0;
568*70a7681dSMarek Vasut 
569*70a7681dSMarek Vasut 	/* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
570*70a7681dSMarek Vasut 	if (!priv->chip->has_firmware_proto)
571*70a7681dSMarek Vasut 		return 0;
572*70a7681dSMarek Vasut 
573*70a7681dSMarek Vasut 	return attr->mode;
574cc12ba18SSven Van Asbroeck }
575cc12ba18SSven Van Asbroeck 
5765c6a7a62SOlivier Sobrie static const struct attribute_group ili210x_attr_group = {
5775c6a7a62SOlivier Sobrie 	.attrs = ili210x_attributes,
578*70a7681dSMarek Vasut 	.is_visible = ili210x_attributes_visible,
5795c6a7a62SOlivier Sobrie };
5805c6a7a62SOlivier Sobrie 
581201f3c80SMarek Vasut static void ili210x_power_down(void *data)
582201f3c80SMarek Vasut {
583201f3c80SMarek Vasut 	struct gpio_desc *reset_gpio = data;
584201f3c80SMarek Vasut 
585201f3c80SMarek Vasut 	gpiod_set_value_cansleep(reset_gpio, 1);
586201f3c80SMarek Vasut }
587201f3c80SMarek Vasut 
58871f8e38aSDmitry Torokhov static void ili210x_stop(void *data)
5891bdec5d9SMarek Vasut {
5901bdec5d9SMarek Vasut 	struct ili210x *priv = data;
5911bdec5d9SMarek Vasut 
59271f8e38aSDmitry Torokhov 	/* Tell ISR to quit even if there is a contact. */
59371f8e38aSDmitry Torokhov 	priv->stop = true;
5941bdec5d9SMarek Vasut }
5951bdec5d9SMarek Vasut 
5965298cc4cSBill Pemberton static int ili210x_i2c_probe(struct i2c_client *client,
5975c6a7a62SOlivier Sobrie 			     const struct i2c_device_id *id)
5985c6a7a62SOlivier Sobrie {
5995c6a7a62SOlivier Sobrie 	struct device *dev = &client->dev;
600ef536abdSDmitry Torokhov 	const struct ili2xxx_chip *chip;
6015c6a7a62SOlivier Sobrie 	struct ili210x *priv;
602201f3c80SMarek Vasut 	struct gpio_desc *reset_gpio;
6035c6a7a62SOlivier Sobrie 	struct input_dev *input;
6045c6a7a62SOlivier Sobrie 	int error;
605b32fbeaeSSven Van Asbroeck 	unsigned int max_xy;
6065c6a7a62SOlivier Sobrie 
6075c6a7a62SOlivier Sobrie 	dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
6085c6a7a62SOlivier Sobrie 
609ef536abdSDmitry Torokhov 	chip = device_get_match_data(dev);
610ef536abdSDmitry Torokhov 	if (!chip && id)
611ef536abdSDmitry Torokhov 		chip = (const struct ili2xxx_chip *)id->driver_data;
612ef536abdSDmitry Torokhov 	if (!chip) {
613ef536abdSDmitry Torokhov 		dev_err(&client->dev, "unknown device model\n");
614ef536abdSDmitry Torokhov 		return -ENODEV;
615ef536abdSDmitry Torokhov 	}
616ef536abdSDmitry Torokhov 
6175c6a7a62SOlivier Sobrie 	if (client->irq <= 0) {
6185c6a7a62SOlivier Sobrie 		dev_err(dev, "No IRQ!\n");
6195c6a7a62SOlivier Sobrie 		return -EINVAL;
6205c6a7a62SOlivier Sobrie 	}
6215c6a7a62SOlivier Sobrie 
622201f3c80SMarek Vasut 	reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
623201f3c80SMarek Vasut 	if (IS_ERR(reset_gpio))
624201f3c80SMarek Vasut 		return PTR_ERR(reset_gpio);
625201f3c80SMarek Vasut 
626201f3c80SMarek Vasut 	if (reset_gpio) {
627201f3c80SMarek Vasut 		error = devm_add_action_or_reset(dev, ili210x_power_down,
628201f3c80SMarek Vasut 						 reset_gpio);
629201f3c80SMarek Vasut 		if (error)
630201f3c80SMarek Vasut 			return error;
631201f3c80SMarek Vasut 
632201f3c80SMarek Vasut 		usleep_range(50, 100);
633201f3c80SMarek Vasut 		gpiod_set_value_cansleep(reset_gpio, 0);
634201f3c80SMarek Vasut 		msleep(100);
635201f3c80SMarek Vasut 	}
636201f3c80SMarek Vasut 
63712294577SMarek Vasut 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
63812294577SMarek Vasut 	if (!priv)
63912294577SMarek Vasut 		return -ENOMEM;
64012294577SMarek Vasut 
64112294577SMarek Vasut 	input = devm_input_allocate_device(dev);
64212294577SMarek Vasut 	if (!input)
64312294577SMarek Vasut 		return -ENOMEM;
64412294577SMarek Vasut 
64512294577SMarek Vasut 	priv->client = client;
64612294577SMarek Vasut 	priv->input = input;
64712294577SMarek Vasut 	priv->reset_gpio = reset_gpio;
648ef536abdSDmitry Torokhov 	priv->chip = chip;
64912294577SMarek Vasut 	i2c_set_clientdata(client, priv);
65012294577SMarek Vasut 
6515c6a7a62SOlivier Sobrie 	/* Setup input device */
6525c6a7a62SOlivier Sobrie 	input->name = "ILI210x Touchscreen";
6535c6a7a62SOlivier Sobrie 	input->id.bustype = BUS_I2C;
6545c6a7a62SOlivier Sobrie 
6555c6a7a62SOlivier Sobrie 	/* Multi touch */
656b32fbeaeSSven Van Asbroeck 	max_xy = (chip->resolution ?: SZ_64K) - 1;
657b32fbeaeSSven Van Asbroeck 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0);
658b32fbeaeSSven Van Asbroeck 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0);
65960159e9eSMarek Vasut 	if (priv->chip->has_pressure_reg)
66060159e9eSMarek Vasut 		input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
661235300edSMarek Vasut 	error = ili251x_firmware_update_cached_state(dev);
662235300edSMarek Vasut 	if (error) {
663235300edSMarek Vasut 		dev_err(dev, "Unable to cache firmware information, err: %d\n",
664235300edSMarek Vasut 			error);
665235300edSMarek Vasut 		return error;
666235300edSMarek Vasut 	}
667f67cc3e9SMarek Vasut 	touchscreen_parse_properties(input, true, &priv->prop);
66843f06a4cSDmitry Torokhov 
669ef536abdSDmitry Torokhov 	error = input_mt_init_slots(input, priv->chip->max_touches,
670ef536abdSDmitry Torokhov 				    INPUT_MT_DIRECT);
67143f06a4cSDmitry Torokhov 	if (error) {
67243f06a4cSDmitry Torokhov 		dev_err(dev, "Unable to set up slots, err: %d\n", error);
67343f06a4cSDmitry Torokhov 		return error;
67443f06a4cSDmitry Torokhov 	}
6755c6a7a62SOlivier Sobrie 
67671f8e38aSDmitry Torokhov 	error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
67771f8e38aSDmitry Torokhov 					  IRQF_ONESHOT, client->name, priv);
6785c6a7a62SOlivier Sobrie 	if (error) {
6795c6a7a62SOlivier Sobrie 		dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
6805c6a7a62SOlivier Sobrie 			error);
6811bdec5d9SMarek Vasut 		return error;
6825c6a7a62SOlivier Sobrie 	}
6835c6a7a62SOlivier Sobrie 
68471f8e38aSDmitry Torokhov 	error = devm_add_action_or_reset(dev, ili210x_stop, priv);
68571f8e38aSDmitry Torokhov 	if (error)
68671f8e38aSDmitry Torokhov 		return error;
68771f8e38aSDmitry Torokhov 
688576057bfSDmitry Torokhov 	error = devm_device_add_group(dev, &ili210x_attr_group);
6895c6a7a62SOlivier Sobrie 	if (error) {
6905c6a7a62SOlivier Sobrie 		dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
6915c6a7a62SOlivier Sobrie 			error);
6921bdec5d9SMarek Vasut 		return error;
6935c6a7a62SOlivier Sobrie 	}
6945c6a7a62SOlivier Sobrie 
6955c6a7a62SOlivier Sobrie 	error = input_register_device(priv->input);
6965c6a7a62SOlivier Sobrie 	if (error) {
697971bd8faSMasanari Iida 		dev_err(dev, "Cannot register input device, err: %d\n", error);
698576057bfSDmitry Torokhov 		return error;
6995c6a7a62SOlivier Sobrie 	}
7005c6a7a62SOlivier Sobrie 
7015c6a7a62SOlivier Sobrie 	return 0;
7025c6a7a62SOlivier Sobrie }
7035c6a7a62SOlivier Sobrie 
7045c6a7a62SOlivier Sobrie static const struct i2c_device_id ili210x_i2c_id[] = {
705ef536abdSDmitry Torokhov 	{ "ili210x", (long)&ili210x_chip },
706ef536abdSDmitry Torokhov 	{ "ili2117", (long)&ili211x_chip },
707d0c5e7d4SLuca Weiss 	{ "ili2120", (long)&ili212x_chip },
708ef536abdSDmitry Torokhov 	{ "ili251x", (long)&ili251x_chip },
7095c6a7a62SOlivier Sobrie 	{ }
7105c6a7a62SOlivier Sobrie };
7115c6a7a62SOlivier Sobrie MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
7125c6a7a62SOlivier Sobrie 
713c5d0e4b5SMarek Vasut static const struct of_device_id ili210x_dt_ids[] = {
714ef536abdSDmitry Torokhov 	{ .compatible = "ilitek,ili210x", .data = &ili210x_chip },
715ef536abdSDmitry Torokhov 	{ .compatible = "ilitek,ili2117", .data = &ili211x_chip },
716d0c5e7d4SLuca Weiss 	{ .compatible = "ilitek,ili2120", .data = &ili212x_chip },
717ef536abdSDmitry Torokhov 	{ .compatible = "ilitek,ili251x", .data = &ili251x_chip },
718ef536abdSDmitry Torokhov 	{ }
719c5d0e4b5SMarek Vasut };
720c5d0e4b5SMarek Vasut MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
721c5d0e4b5SMarek Vasut 
7225c6a7a62SOlivier Sobrie static struct i2c_driver ili210x_ts_driver = {
7235c6a7a62SOlivier Sobrie 	.driver = {
7245c6a7a62SOlivier Sobrie 		.name = "ili210x_i2c",
725c5d0e4b5SMarek Vasut 		.of_match_table = ili210x_dt_ids,
7265c6a7a62SOlivier Sobrie 	},
7275c6a7a62SOlivier Sobrie 	.id_table = ili210x_i2c_id,
7285c6a7a62SOlivier Sobrie 	.probe = ili210x_i2c_probe,
7295c6a7a62SOlivier Sobrie };
7305c6a7a62SOlivier Sobrie 
7315c6a7a62SOlivier Sobrie module_i2c_driver(ili210x_ts_driver);
7325c6a7a62SOlivier Sobrie 
7335c6a7a62SOlivier Sobrie MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
7345c6a7a62SOlivier Sobrie MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
7355c6a7a62SOlivier Sobrie MODULE_LICENSE("GPL");
736