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