1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2902cb3afSSébastien Szymanski /*
3902cb3afSSébastien Szymanski  * Driver for Semtech SX8654 I2C touchscreen controller.
4902cb3afSSébastien Szymanski  *
5902cb3afSSébastien Szymanski  * Copyright (c) 2015 Armadeus Systems
6902cb3afSSébastien Szymanski  *	Sébastien Szymanski <sebastien.szymanski@armadeus.com>
7902cb3afSSébastien Szymanski  *
8902cb3afSSébastien Szymanski  * Using code from:
9902cb3afSSébastien Szymanski  *  - sx865x.c
10902cb3afSSébastien Szymanski  *	Copyright (c) 2013 U-MoBo Srl
11902cb3afSSébastien Szymanski  *	Pierluigi Passaro <p.passaro@u-mobo.com>
12902cb3afSSébastien Szymanski  *  - sx8650.c
13902cb3afSSébastien Szymanski  *      Copyright (c) 2009 Wayne Roberts
14902cb3afSSébastien Szymanski  *  - tsc2007.c
15902cb3afSSébastien Szymanski  *      Copyright (c) 2008 Kwangwoo Lee
16902cb3afSSébastien Szymanski  *  - ads7846.c
17902cb3afSSébastien Szymanski  *      Copyright (c) 2005 David Brownell
18902cb3afSSébastien Szymanski  *      Copyright (c) 2006 Nokia Corporation
19902cb3afSSébastien Szymanski  *  - corgi_ts.c
20902cb3afSSébastien Szymanski  *      Copyright (C) 2004-2005 Richard Purdie
21902cb3afSSébastien Szymanski  *  - omap_ts.[hc], ads7846.h, ts_osk.c
22902cb3afSSébastien Szymanski  *      Copyright (C) 2002 MontaVista Software
23902cb3afSSébastien Szymanski  *      Copyright (C) 2004 Texas Instruments
24902cb3afSSébastien Szymanski  *      Copyright (C) 2005 Dirk Behme
25902cb3afSSébastien Szymanski  */
26902cb3afSSébastien Szymanski 
27e47ff893SRichard Leitner #include <linux/bitops.h>
28c3a39380SRichard Leitner #include <linux/delay.h>
29c3a39380SRichard Leitner #include <linux/gpio/consumer.h>
30902cb3afSSébastien Szymanski #include <linux/i2c.h>
31c3a39380SRichard Leitner #include <linux/input.h>
324ec90ac5SRichard Leitner #include <linux/input/touchscreen.h>
33902cb3afSSébastien Szymanski #include <linux/interrupt.h>
34902cb3afSSébastien Szymanski #include <linux/irq.h>
35c3a39380SRichard Leitner #include <linux/module.h>
36c3a39380SRichard Leitner #include <linux/of.h>
37902cb3afSSébastien Szymanski 
38902cb3afSSébastien Szymanski /* register addresses */
39902cb3afSSébastien Szymanski #define I2C_REG_TOUCH0			0x00
40902cb3afSSébastien Szymanski #define I2C_REG_TOUCH1			0x01
41902cb3afSSébastien Szymanski #define I2C_REG_CHANMASK		0x04
42902cb3afSSébastien Szymanski #define I2C_REG_IRQMASK			0x22
43902cb3afSSébastien Szymanski #define I2C_REG_IRQSRC			0x23
44902cb3afSSébastien Szymanski #define I2C_REG_SOFTRESET		0x3f
45902cb3afSSébastien Szymanski 
4643df039cSRichard Leitner #define I2C_REG_SX8650_STAT		0x05
47e47ff893SRichard Leitner #define SX8650_STAT_CONVIRQ		BIT(7)
4843df039cSRichard Leitner 
49902cb3afSSébastien Szymanski /* commands */
50902cb3afSSébastien Szymanski #define CMD_READ_REGISTER		0x40
51902cb3afSSébastien Szymanski #define CMD_PENTRG			0xe0
52902cb3afSSébastien Szymanski 
53902cb3afSSébastien Szymanski /* value for I2C_REG_SOFTRESET */
54902cb3afSSébastien Szymanski #define SOFTRESET_VALUE			0xde
55902cb3afSSébastien Szymanski 
56902cb3afSSébastien Szymanski /* bits for I2C_REG_IRQSRC */
57e47ff893SRichard Leitner #define IRQ_PENTOUCH_TOUCHCONVDONE	BIT(3)
58e47ff893SRichard Leitner #define IRQ_PENRELEASE			BIT(2)
59902cb3afSSébastien Szymanski 
60902cb3afSSébastien Szymanski /* bits for RegTouch1 */
61902cb3afSSébastien Szymanski #define CONDIRQ				0x20
6243df039cSRichard Leitner #define RPDNT_100K			0x00
63902cb3afSSébastien Szymanski #define FILT_7SA			0x03
64902cb3afSSébastien Szymanski 
65902cb3afSSébastien Szymanski /* bits for I2C_REG_CHANMASK */
66e47ff893SRichard Leitner #define CONV_X				BIT(7)
67e47ff893SRichard Leitner #define CONV_Y				BIT(6)
68902cb3afSSébastien Szymanski 
69902cb3afSSébastien Szymanski /* coordinates rate: higher nibble of CTRL0 register */
70902cb3afSSébastien Szymanski #define RATE_MANUAL			0x00
71902cb3afSSébastien Szymanski #define RATE_5000CPS			0xf0
72902cb3afSSébastien Szymanski 
73902cb3afSSébastien Szymanski /* power delay: lower nibble of CTRL0 register */
74902cb3afSSébastien Szymanski #define POWDLY_1_1MS			0x0b
75902cb3afSSébastien Szymanski 
7643df039cSRichard Leitner /* for sx8650, as we have no pen release IRQ there: timeout in ns following the
7743df039cSRichard Leitner  * last PENIRQ after which we assume the pen is lifted.
7843df039cSRichard Leitner  */
7943df039cSRichard Leitner #define SX8650_PENIRQ_TIMEOUT		msecs_to_jiffies(10)
8043df039cSRichard Leitner 
81902cb3afSSébastien Szymanski #define MAX_12BIT			((1 << 12) - 1)
8243df039cSRichard Leitner #define MAX_I2C_READ_LEN		10 /* see datasheet section 5.1.5 */
8343df039cSRichard Leitner 
8443df039cSRichard Leitner /* channel definition */
8543df039cSRichard Leitner #define CH_X				0x00
8643df039cSRichard Leitner #define CH_Y				0x01
8743df039cSRichard Leitner 
8843df039cSRichard Leitner struct sx865x_data {
8943df039cSRichard Leitner 	u8 cmd_manual;
9043df039cSRichard Leitner 	u8 chan_mask;
9143df039cSRichard Leitner 	bool has_irq_penrelease;
9243df039cSRichard Leitner 	bool has_reg_irqmask;
9343df039cSRichard Leitner 	irq_handler_t irqh;
9443df039cSRichard Leitner };
95902cb3afSSébastien Szymanski 
96902cb3afSSébastien Szymanski struct sx8654 {
97902cb3afSSébastien Szymanski 	struct input_dev *input;
98902cb3afSSébastien Szymanski 	struct i2c_client *client;
99c3a39380SRichard Leitner 	struct gpio_desc *gpio_reset;
10043df039cSRichard Leitner 
10143df039cSRichard Leitner 	spinlock_t lock;	/* for input reporting from irq/timer */
10243df039cSRichard Leitner 	struct timer_list timer;
10343df039cSRichard Leitner 
1044ec90ac5SRichard Leitner 	struct touchscreen_properties props;
1054ec90ac5SRichard Leitner 
10643df039cSRichard Leitner 	const struct sx865x_data *data;
107902cb3afSSébastien Szymanski };
108902cb3afSSébastien Szymanski 
sx865x_penrelease(struct sx8654 * ts)10943df039cSRichard Leitner static inline void sx865x_penrelease(struct sx8654 *ts)
11043df039cSRichard Leitner {
11143df039cSRichard Leitner 	struct input_dev *input_dev = ts->input;
11243df039cSRichard Leitner 
11343df039cSRichard Leitner 	input_report_key(input_dev, BTN_TOUCH, 0);
11443df039cSRichard Leitner 	input_sync(input_dev);
11543df039cSRichard Leitner }
11643df039cSRichard Leitner 
sx865x_penrelease_timer_handler(struct timer_list * t)11743df039cSRichard Leitner static void sx865x_penrelease_timer_handler(struct timer_list *t)
11843df039cSRichard Leitner {
11943df039cSRichard Leitner 	struct sx8654 *ts = from_timer(ts, t, timer);
12043df039cSRichard Leitner 	unsigned long flags;
12143df039cSRichard Leitner 
12243df039cSRichard Leitner 	spin_lock_irqsave(&ts->lock, flags);
12343df039cSRichard Leitner 	sx865x_penrelease(ts);
12443df039cSRichard Leitner 	spin_unlock_irqrestore(&ts->lock, flags);
12543df039cSRichard Leitner 	dev_dbg(&ts->client->dev, "penrelease by timer\n");
12643df039cSRichard Leitner }
12743df039cSRichard Leitner 
sx8650_irq(int irq,void * handle)12843df039cSRichard Leitner static irqreturn_t sx8650_irq(int irq, void *handle)
12943df039cSRichard Leitner {
13043df039cSRichard Leitner 	struct sx8654 *ts = handle;
13143df039cSRichard Leitner 	struct device *dev = &ts->client->dev;
13243df039cSRichard Leitner 	int len, i;
13343df039cSRichard Leitner 	unsigned long flags;
13443df039cSRichard Leitner 	u8 stat;
13543df039cSRichard Leitner 	u16 x, y;
13643df039cSRichard Leitner 	u16 ch;
13743df039cSRichard Leitner 	u16 chdata;
13843df039cSRichard Leitner 	__be16 data[MAX_I2C_READ_LEN / sizeof(__be16)];
13943df039cSRichard Leitner 	u8 nchan = hweight32(ts->data->chan_mask);
14043df039cSRichard Leitner 	u8 readlen = nchan * sizeof(*data);
14143df039cSRichard Leitner 
14243df039cSRichard Leitner 	stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER
14343df039cSRichard Leitner 						    | I2C_REG_SX8650_STAT);
14443df039cSRichard Leitner 
14543df039cSRichard Leitner 	if (!(stat & SX8650_STAT_CONVIRQ)) {
14643df039cSRichard Leitner 		dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat);
14743df039cSRichard Leitner 		return IRQ_HANDLED;
14843df039cSRichard Leitner 	}
14943df039cSRichard Leitner 
15043df039cSRichard Leitner 	len = i2c_master_recv(ts->client, (u8 *)data, readlen);
15143df039cSRichard Leitner 	if (len != readlen) {
15243df039cSRichard Leitner 		dev_dbg(dev, "ignore short recv (%d)\n", len);
15343df039cSRichard Leitner 		return IRQ_HANDLED;
15443df039cSRichard Leitner 	}
15543df039cSRichard Leitner 
15643df039cSRichard Leitner 	spin_lock_irqsave(&ts->lock, flags);
15743df039cSRichard Leitner 
15843df039cSRichard Leitner 	x = 0;
15943df039cSRichard Leitner 	y = 0;
16043df039cSRichard Leitner 	for (i = 0; i < nchan; i++) {
16143df039cSRichard Leitner 		chdata = be16_to_cpu(data[i]);
16243df039cSRichard Leitner 
16343df039cSRichard Leitner 		if (unlikely(chdata == 0xFFFF)) {
16443df039cSRichard Leitner 			dev_dbg(dev, "invalid qualified data @ %d\n", i);
16543df039cSRichard Leitner 			continue;
16643df039cSRichard Leitner 		} else if (unlikely(chdata & 0x8000)) {
16743df039cSRichard Leitner 			dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata);
16843df039cSRichard Leitner 			continue;
16943df039cSRichard Leitner 		}
17043df039cSRichard Leitner 
17143df039cSRichard Leitner 		ch = chdata >> 12;
17243df039cSRichard Leitner 		if (ch == CH_X)
17343df039cSRichard Leitner 			x = chdata & MAX_12BIT;
17443df039cSRichard Leitner 		else if (ch == CH_Y)
17543df039cSRichard Leitner 			y = chdata & MAX_12BIT;
17643df039cSRichard Leitner 		else
17743df039cSRichard Leitner 			dev_warn(dev, "unknown channel %d [0x%04x]\n", ch,
17843df039cSRichard Leitner 				 chdata);
17943df039cSRichard Leitner 	}
18043df039cSRichard Leitner 
1814ec90ac5SRichard Leitner 	touchscreen_report_pos(ts->input, &ts->props, x, y, false);
18243df039cSRichard Leitner 	input_report_key(ts->input, BTN_TOUCH, 1);
18343df039cSRichard Leitner 	input_sync(ts->input);
18443df039cSRichard Leitner 	dev_dbg(dev, "point(%4d,%4d)\n", x, y);
18543df039cSRichard Leitner 
18643df039cSRichard Leitner 	mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT);
18743df039cSRichard Leitner 	spin_unlock_irqrestore(&ts->lock, flags);
18843df039cSRichard Leitner 
18943df039cSRichard Leitner 	return IRQ_HANDLED;
19043df039cSRichard Leitner }
19143df039cSRichard Leitner 
sx8654_irq(int irq,void * handle)192902cb3afSSébastien Szymanski static irqreturn_t sx8654_irq(int irq, void *handle)
193902cb3afSSébastien Szymanski {
194902cb3afSSébastien Szymanski 	struct sx8654 *sx8654 = handle;
195b6310affSDan Carpenter 	int irqsrc;
196902cb3afSSébastien Szymanski 	u8 data[4];
197902cb3afSSébastien Szymanski 	unsigned int x, y;
198902cb3afSSébastien Szymanski 	int retval;
199902cb3afSSébastien Szymanski 
200902cb3afSSébastien Szymanski 	irqsrc = i2c_smbus_read_byte_data(sx8654->client,
201902cb3afSSébastien Szymanski 					  CMD_READ_REGISTER | I2C_REG_IRQSRC);
202902cb3afSSébastien Szymanski 	dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
203902cb3afSSébastien Szymanski 
204902cb3afSSébastien Szymanski 	if (irqsrc < 0)
205902cb3afSSébastien Szymanski 		goto out;
206902cb3afSSébastien Szymanski 
207902cb3afSSébastien Szymanski 	if (irqsrc & IRQ_PENRELEASE) {
208902cb3afSSébastien Szymanski 		dev_dbg(&sx8654->client->dev, "pen release interrupt");
209902cb3afSSébastien Szymanski 
210902cb3afSSébastien Szymanski 		input_report_key(sx8654->input, BTN_TOUCH, 0);
211902cb3afSSébastien Szymanski 		input_sync(sx8654->input);
212902cb3afSSébastien Szymanski 	}
213902cb3afSSébastien Szymanski 
214902cb3afSSébastien Szymanski 	if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
215902cb3afSSébastien Szymanski 		dev_dbg(&sx8654->client->dev, "pen touch interrupt");
216902cb3afSSébastien Szymanski 
217902cb3afSSébastien Szymanski 		retval = i2c_master_recv(sx8654->client, data, sizeof(data));
218902cb3afSSébastien Szymanski 		if (retval != sizeof(data))
219902cb3afSSébastien Szymanski 			goto out;
220902cb3afSSébastien Szymanski 
221902cb3afSSébastien Szymanski 		/* invalid data */
222902cb3afSSébastien Szymanski 		if (unlikely(data[0] & 0x80 || data[2] & 0x80))
223902cb3afSSébastien Szymanski 			goto out;
224902cb3afSSébastien Szymanski 
225902cb3afSSébastien Szymanski 		x = ((data[0] & 0xf) << 8) | (data[1]);
226902cb3afSSébastien Szymanski 		y = ((data[2] & 0xf) << 8) | (data[3]);
227902cb3afSSébastien Szymanski 
2284ec90ac5SRichard Leitner 		touchscreen_report_pos(sx8654->input, &sx8654->props, x, y,
2294ec90ac5SRichard Leitner 				       false);
230902cb3afSSébastien Szymanski 		input_report_key(sx8654->input, BTN_TOUCH, 1);
231902cb3afSSébastien Szymanski 		input_sync(sx8654->input);
232902cb3afSSébastien Szymanski 
233902cb3afSSébastien Szymanski 		dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
234902cb3afSSébastien Szymanski 	}
235902cb3afSSébastien Szymanski 
236902cb3afSSébastien Szymanski out:
237902cb3afSSébastien Szymanski 	return IRQ_HANDLED;
238902cb3afSSébastien Szymanski }
239902cb3afSSébastien Szymanski 
sx8654_reset(struct sx8654 * ts)240c3a39380SRichard Leitner static int sx8654_reset(struct sx8654 *ts)
241c3a39380SRichard Leitner {
242c3a39380SRichard Leitner 	int err;
243c3a39380SRichard Leitner 
244c3a39380SRichard Leitner 	if (ts->gpio_reset) {
245c3a39380SRichard Leitner 		gpiod_set_value_cansleep(ts->gpio_reset, 1);
246c3a39380SRichard Leitner 		udelay(2); /* Tpulse > 1µs */
247c3a39380SRichard Leitner 		gpiod_set_value_cansleep(ts->gpio_reset, 0);
248c3a39380SRichard Leitner 	} else {
249c3a39380SRichard Leitner 		dev_dbg(&ts->client->dev, "NRST unavailable, try softreset\n");
250c3a39380SRichard Leitner 		err = i2c_smbus_write_byte_data(ts->client, I2C_REG_SOFTRESET,
251c3a39380SRichard Leitner 						SOFTRESET_VALUE);
252c3a39380SRichard Leitner 		if (err)
253c3a39380SRichard Leitner 			return err;
254c3a39380SRichard Leitner 	}
255c3a39380SRichard Leitner 
256c3a39380SRichard Leitner 	return 0;
257c3a39380SRichard Leitner }
258c3a39380SRichard Leitner 
sx8654_open(struct input_dev * dev)259902cb3afSSébastien Szymanski static int sx8654_open(struct input_dev *dev)
260902cb3afSSébastien Szymanski {
261902cb3afSSébastien Szymanski 	struct sx8654 *sx8654 = input_get_drvdata(dev);
262902cb3afSSébastien Szymanski 	struct i2c_client *client = sx8654->client;
263902cb3afSSébastien Szymanski 	int error;
264902cb3afSSébastien Szymanski 
265902cb3afSSébastien Szymanski 	/* enable pen trigger mode */
266902cb3afSSébastien Szymanski 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
267902cb3afSSébastien Szymanski 					  RATE_5000CPS | POWDLY_1_1MS);
268902cb3afSSébastien Szymanski 	if (error) {
269902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
270902cb3afSSébastien Szymanski 		return error;
271902cb3afSSébastien Szymanski 	}
272902cb3afSSébastien Szymanski 
273902cb3afSSébastien Szymanski 	error = i2c_smbus_write_byte(client, CMD_PENTRG);
274902cb3afSSébastien Szymanski 	if (error) {
275902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing command CMD_PENTRG failed");
276902cb3afSSébastien Szymanski 		return error;
277902cb3afSSébastien Szymanski 	}
278902cb3afSSébastien Szymanski 
279902cb3afSSébastien Szymanski 	enable_irq(client->irq);
280902cb3afSSébastien Szymanski 
281902cb3afSSébastien Szymanski 	return 0;
282902cb3afSSébastien Szymanski }
283902cb3afSSébastien Szymanski 
sx8654_close(struct input_dev * dev)284902cb3afSSébastien Szymanski static void sx8654_close(struct input_dev *dev)
285902cb3afSSébastien Szymanski {
286902cb3afSSébastien Szymanski 	struct sx8654 *sx8654 = input_get_drvdata(dev);
287902cb3afSSébastien Szymanski 	struct i2c_client *client = sx8654->client;
288902cb3afSSébastien Szymanski 	int error;
289902cb3afSSébastien Szymanski 
290902cb3afSSébastien Szymanski 	disable_irq(client->irq);
291902cb3afSSébastien Szymanski 
29243df039cSRichard Leitner 	if (!sx8654->data->has_irq_penrelease)
29343df039cSRichard Leitner 		del_timer_sync(&sx8654->timer);
29443df039cSRichard Leitner 
295902cb3afSSébastien Szymanski 	/* enable manual mode mode */
29643df039cSRichard Leitner 	error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
297902cb3afSSébastien Szymanski 	if (error) {
298902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing command CMD_MANUAL failed");
299902cb3afSSébastien Szymanski 		return;
300902cb3afSSébastien Szymanski 	}
301902cb3afSSébastien Szymanski 
30243df039cSRichard Leitner 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, RATE_MANUAL);
303902cb3afSSébastien Szymanski 	if (error) {
304902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
305902cb3afSSébastien Szymanski 		return;
306902cb3afSSébastien Szymanski 	}
307902cb3afSSébastien Szymanski }
308902cb3afSSébastien Szymanski 
sx8654_probe(struct i2c_client * client)309bc0bbf91SUwe Kleine-König static int sx8654_probe(struct i2c_client *client)
310902cb3afSSébastien Szymanski {
311bc0bbf91SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
312902cb3afSSébastien Szymanski 	struct sx8654 *sx8654;
313902cb3afSSébastien Szymanski 	struct input_dev *input;
314902cb3afSSébastien Szymanski 	int error;
315902cb3afSSébastien Szymanski 
316902cb3afSSébastien Szymanski 	if (!i2c_check_functionality(client->adapter,
317902cb3afSSébastien Szymanski 				     I2C_FUNC_SMBUS_READ_WORD_DATA))
318902cb3afSSébastien Szymanski 		return -ENXIO;
319902cb3afSSébastien Szymanski 
320902cb3afSSébastien Szymanski 	sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
321902cb3afSSébastien Szymanski 	if (!sx8654)
322902cb3afSSébastien Szymanski 		return -ENOMEM;
323902cb3afSSébastien Szymanski 
324c3a39380SRichard Leitner 	sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
325c3a39380SRichard Leitner 						     GPIOD_OUT_HIGH);
326*337ac36cSKrzysztof Kozlowski 	if (IS_ERR(sx8654->gpio_reset))
327*337ac36cSKrzysztof Kozlowski 		return dev_err_probe(&client->dev, PTR_ERR(sx8654->gpio_reset),
328*337ac36cSKrzysztof Kozlowski 				     "unable to get reset-gpio\n");
329c3a39380SRichard Leitner 	dev_dbg(&client->dev, "got GPIO reset pin\n");
330c3a39380SRichard Leitner 
33143df039cSRichard Leitner 	sx8654->data = device_get_match_data(&client->dev);
33243df039cSRichard Leitner 	if (!sx8654->data)
33343df039cSRichard Leitner 		sx8654->data = (const struct sx865x_data *)id->driver_data;
33443df039cSRichard Leitner 	if (!sx8654->data) {
33543df039cSRichard Leitner 		dev_err(&client->dev, "invalid or missing device data\n");
33643df039cSRichard Leitner 		return -EINVAL;
33743df039cSRichard Leitner 	}
33843df039cSRichard Leitner 
33943df039cSRichard Leitner 	if (!sx8654->data->has_irq_penrelease) {
34043df039cSRichard Leitner 		dev_dbg(&client->dev, "use timer for penrelease\n");
34143df039cSRichard Leitner 		timer_setup(&sx8654->timer, sx865x_penrelease_timer_handler, 0);
34243df039cSRichard Leitner 		spin_lock_init(&sx8654->lock);
34343df039cSRichard Leitner 	}
34443df039cSRichard Leitner 
345902cb3afSSébastien Szymanski 	input = devm_input_allocate_device(&client->dev);
34622ffc3e4SDmitry Torokhov 	if (!input)
347902cb3afSSébastien Szymanski 		return -ENOMEM;
348902cb3afSSébastien Szymanski 
349902cb3afSSébastien Szymanski 	input->name = "SX8654 I2C Touchscreen";
350902cb3afSSébastien Szymanski 	input->id.bustype = BUS_I2C;
351902cb3afSSébastien Szymanski 	input->dev.parent = &client->dev;
352902cb3afSSébastien Szymanski 	input->open = sx8654_open;
353902cb3afSSébastien Szymanski 	input->close = sx8654_close;
354902cb3afSSébastien Szymanski 
355902cb3afSSébastien Szymanski 	__set_bit(INPUT_PROP_DIRECT, input->propbit);
356902cb3afSSébastien Szymanski 	input_set_capability(input, EV_KEY, BTN_TOUCH);
357902cb3afSSébastien Szymanski 	input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
358902cb3afSSébastien Szymanski 	input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
359902cb3afSSébastien Szymanski 
3604ec90ac5SRichard Leitner 	touchscreen_parse_properties(input, false, &sx8654->props);
3614ec90ac5SRichard Leitner 
362902cb3afSSébastien Szymanski 	sx8654->client = client;
363902cb3afSSébastien Szymanski 	sx8654->input = input;
364902cb3afSSébastien Szymanski 
365902cb3afSSébastien Szymanski 	input_set_drvdata(sx8654->input, sx8654);
366902cb3afSSébastien Szymanski 
367c3a39380SRichard Leitner 	error = sx8654_reset(sx8654);
368902cb3afSSébastien Szymanski 	if (error) {
369c3a39380SRichard Leitner 		dev_err(&client->dev, "reset failed");
370902cb3afSSébastien Szymanski 		return error;
371902cb3afSSébastien Szymanski 	}
372902cb3afSSébastien Szymanski 
373902cb3afSSébastien Szymanski 	error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
37443df039cSRichard Leitner 					  sx8654->data->chan_mask);
375902cb3afSSébastien Szymanski 	if (error) {
376902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
377902cb3afSSébastien Szymanski 		return error;
378902cb3afSSébastien Szymanski 	}
379902cb3afSSébastien Szymanski 
38043df039cSRichard Leitner 	if (sx8654->data->has_reg_irqmask) {
381902cb3afSSébastien Szymanski 		error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
382902cb3afSSébastien Szymanski 						  IRQ_PENTOUCH_TOUCHCONVDONE |
383902cb3afSSébastien Szymanski 							IRQ_PENRELEASE);
384902cb3afSSébastien Szymanski 		if (error) {
38543df039cSRichard Leitner 			dev_err(&client->dev, "writing I2C_REG_IRQMASK failed");
386902cb3afSSébastien Szymanski 			return error;
387902cb3afSSébastien Szymanski 		}
38843df039cSRichard Leitner 	}
389902cb3afSSébastien Szymanski 
390902cb3afSSébastien Szymanski 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
39143df039cSRichard Leitner 					  CONDIRQ | RPDNT_100K | FILT_7SA);
392902cb3afSSébastien Szymanski 	if (error) {
393902cb3afSSébastien Szymanski 		dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
394902cb3afSSébastien Szymanski 		return error;
395902cb3afSSébastien Szymanski 	}
396902cb3afSSébastien Szymanski 
397902cb3afSSébastien Szymanski 	error = devm_request_threaded_irq(&client->dev, client->irq,
39843df039cSRichard Leitner 					  NULL, sx8654->data->irqh,
3993c1697e6SDmitry Torokhov 					  IRQF_ONESHOT,
400902cb3afSSébastien Szymanski 					  client->name, sx8654);
401902cb3afSSébastien Szymanski 	if (error) {
402902cb3afSSébastien Szymanski 		dev_err(&client->dev,
403902cb3afSSébastien Szymanski 			"Failed to enable IRQ %d, error: %d\n",
404902cb3afSSébastien Szymanski 			client->irq, error);
405902cb3afSSébastien Szymanski 		return error;
406902cb3afSSébastien Szymanski 	}
407902cb3afSSébastien Szymanski 
408902cb3afSSébastien Szymanski 	/* Disable the IRQ, we'll enable it in sx8654_open() */
409902cb3afSSébastien Szymanski 	disable_irq(client->irq);
410902cb3afSSébastien Szymanski 
411902cb3afSSébastien Szymanski 	error = input_register_device(sx8654->input);
412902cb3afSSébastien Szymanski 	if (error)
413902cb3afSSébastien Szymanski 		return error;
414902cb3afSSébastien Szymanski 
415902cb3afSSébastien Szymanski 	return 0;
416902cb3afSSébastien Szymanski }
417902cb3afSSébastien Szymanski 
41843df039cSRichard Leitner static const struct sx865x_data sx8650_data = {
41943df039cSRichard Leitner 	.cmd_manual		= 0xb0,
42043df039cSRichard Leitner 	.has_irq_penrelease	= false,
42143df039cSRichard Leitner 	.has_reg_irqmask	= false,
42243df039cSRichard Leitner 	.chan_mask		= (CONV_X | CONV_Y),
42343df039cSRichard Leitner 	.irqh			= sx8650_irq,
42443df039cSRichard Leitner };
42543df039cSRichard Leitner 
42643df039cSRichard Leitner static const struct sx865x_data sx8654_data = {
42743df039cSRichard Leitner 	.cmd_manual		= 0xc0,
42843df039cSRichard Leitner 	.has_irq_penrelease	= true,
42943df039cSRichard Leitner 	.has_reg_irqmask	= true,
43043df039cSRichard Leitner 	.chan_mask		= (CONV_X | CONV_Y),
43143df039cSRichard Leitner 	.irqh			= sx8654_irq,
43243df039cSRichard Leitner };
43343df039cSRichard Leitner 
434902cb3afSSébastien Szymanski #ifdef CONFIG_OF
435902cb3afSSébastien Szymanski static const struct of_device_id sx8654_of_match[] = {
43643df039cSRichard Leitner 	{
43743df039cSRichard Leitner 		.compatible = "semtech,sx8650",
43843df039cSRichard Leitner 		.data = &sx8650_data,
43943df039cSRichard Leitner 	}, {
44043df039cSRichard Leitner 		.compatible = "semtech,sx8654",
44143df039cSRichard Leitner 		.data = &sx8654_data,
44243df039cSRichard Leitner 	}, {
44343df039cSRichard Leitner 		.compatible = "semtech,sx8655",
44443df039cSRichard Leitner 		.data = &sx8654_data,
44543df039cSRichard Leitner 	}, {
44643df039cSRichard Leitner 		.compatible = "semtech,sx8656",
44743df039cSRichard Leitner 		.data = &sx8654_data,
44843df039cSRichard Leitner 	},
44943df039cSRichard Leitner 	{ }
450902cb3afSSébastien Szymanski };
451902cb3afSSébastien Szymanski MODULE_DEVICE_TABLE(of, sx8654_of_match);
452902cb3afSSébastien Szymanski #endif
453902cb3afSSébastien Szymanski 
454902cb3afSSébastien Szymanski static const struct i2c_device_id sx8654_id_table[] = {
45543df039cSRichard Leitner 	{ .name = "semtech_sx8650", .driver_data = (long)&sx8650_data },
45643df039cSRichard Leitner 	{ .name = "semtech_sx8654", .driver_data = (long)&sx8654_data },
45743df039cSRichard Leitner 	{ .name = "semtech_sx8655", .driver_data = (long)&sx8654_data },
45843df039cSRichard Leitner 	{ .name = "semtech_sx8656", .driver_data = (long)&sx8654_data },
45943df039cSRichard Leitner 	{ }
460902cb3afSSébastien Szymanski };
461902cb3afSSébastien Szymanski MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
462902cb3afSSébastien Szymanski 
463902cb3afSSébastien Szymanski static struct i2c_driver sx8654_driver = {
464902cb3afSSébastien Szymanski 	.driver = {
465902cb3afSSébastien Szymanski 		.name = "sx8654",
466902cb3afSSébastien Szymanski 		.of_match_table = of_match_ptr(sx8654_of_match),
467902cb3afSSébastien Szymanski 	},
468902cb3afSSébastien Szymanski 	.id_table = sx8654_id_table,
469d8bde56dSUwe Kleine-König 	.probe = sx8654_probe,
470902cb3afSSébastien Szymanski };
471902cb3afSSébastien Szymanski module_i2c_driver(sx8654_driver);
472902cb3afSSébastien Szymanski 
473902cb3afSSébastien Szymanski MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
474902cb3afSSébastien Szymanski MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
475902cb3afSSébastien Szymanski MODULE_LICENSE("GPL");
476