18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Semtech SX8654 I2C touchscreen controller.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Armadeus Systems
68c2ecf20Sopenharmony_ci *	Sébastien Szymanski <sebastien.szymanski@armadeus.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Using code from:
98c2ecf20Sopenharmony_ci *  - sx865x.c
108c2ecf20Sopenharmony_ci *	Copyright (c) 2013 U-MoBo Srl
118c2ecf20Sopenharmony_ci *	Pierluigi Passaro <p.passaro@u-mobo.com>
128c2ecf20Sopenharmony_ci *  - sx8650.c
138c2ecf20Sopenharmony_ci *      Copyright (c) 2009 Wayne Roberts
148c2ecf20Sopenharmony_ci *  - tsc2007.c
158c2ecf20Sopenharmony_ci *      Copyright (c) 2008 Kwangwoo Lee
168c2ecf20Sopenharmony_ci *  - ads7846.c
178c2ecf20Sopenharmony_ci *      Copyright (c) 2005 David Brownell
188c2ecf20Sopenharmony_ci *      Copyright (c) 2006 Nokia Corporation
198c2ecf20Sopenharmony_ci *  - corgi_ts.c
208c2ecf20Sopenharmony_ci *      Copyright (C) 2004-2005 Richard Purdie
218c2ecf20Sopenharmony_ci *  - omap_ts.[hc], ads7846.h, ts_osk.c
228c2ecf20Sopenharmony_ci *      Copyright (C) 2002 MontaVista Software
238c2ecf20Sopenharmony_ci *      Copyright (C) 2004 Texas Instruments
248c2ecf20Sopenharmony_ci *      Copyright (C) 2005 Dirk Behme
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/bitops.h>
288c2ecf20Sopenharmony_ci#include <linux/delay.h>
298c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
308c2ecf20Sopenharmony_ci#include <linux/i2c.h>
318c2ecf20Sopenharmony_ci#include <linux/input.h>
328c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h>
338c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
348c2ecf20Sopenharmony_ci#include <linux/irq.h>
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/of.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* register addresses */
398c2ecf20Sopenharmony_ci#define I2C_REG_TOUCH0			0x00
408c2ecf20Sopenharmony_ci#define I2C_REG_TOUCH1			0x01
418c2ecf20Sopenharmony_ci#define I2C_REG_CHANMASK		0x04
428c2ecf20Sopenharmony_ci#define I2C_REG_IRQMASK			0x22
438c2ecf20Sopenharmony_ci#define I2C_REG_IRQSRC			0x23
448c2ecf20Sopenharmony_ci#define I2C_REG_SOFTRESET		0x3f
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define I2C_REG_SX8650_STAT		0x05
478c2ecf20Sopenharmony_ci#define SX8650_STAT_CONVIRQ		BIT(7)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* commands */
508c2ecf20Sopenharmony_ci#define CMD_READ_REGISTER		0x40
518c2ecf20Sopenharmony_ci#define CMD_PENTRG			0xe0
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* value for I2C_REG_SOFTRESET */
548c2ecf20Sopenharmony_ci#define SOFTRESET_VALUE			0xde
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* bits for I2C_REG_IRQSRC */
578c2ecf20Sopenharmony_ci#define IRQ_PENTOUCH_TOUCHCONVDONE	BIT(3)
588c2ecf20Sopenharmony_ci#define IRQ_PENRELEASE			BIT(2)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* bits for RegTouch1 */
618c2ecf20Sopenharmony_ci#define CONDIRQ				0x20
628c2ecf20Sopenharmony_ci#define RPDNT_100K			0x00
638c2ecf20Sopenharmony_ci#define FILT_7SA			0x03
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* bits for I2C_REG_CHANMASK */
668c2ecf20Sopenharmony_ci#define CONV_X				BIT(7)
678c2ecf20Sopenharmony_ci#define CONV_Y				BIT(6)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* coordinates rate: higher nibble of CTRL0 register */
708c2ecf20Sopenharmony_ci#define RATE_MANUAL			0x00
718c2ecf20Sopenharmony_ci#define RATE_5000CPS			0xf0
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* power delay: lower nibble of CTRL0 register */
748c2ecf20Sopenharmony_ci#define POWDLY_1_1MS			0x0b
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* for sx8650, as we have no pen release IRQ there: timeout in ns following the
778c2ecf20Sopenharmony_ci * last PENIRQ after which we assume the pen is lifted.
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_ci#define SX8650_PENIRQ_TIMEOUT		msecs_to_jiffies(10)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define MAX_12BIT			((1 << 12) - 1)
828c2ecf20Sopenharmony_ci#define MAX_I2C_READ_LEN		10 /* see datasheet section 5.1.5 */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/* channel definition */
858c2ecf20Sopenharmony_ci#define CH_X				0x00
868c2ecf20Sopenharmony_ci#define CH_Y				0x01
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistruct sx865x_data {
898c2ecf20Sopenharmony_ci	u8 cmd_manual;
908c2ecf20Sopenharmony_ci	u8 chan_mask;
918c2ecf20Sopenharmony_ci	bool has_irq_penrelease;
928c2ecf20Sopenharmony_ci	bool has_reg_irqmask;
938c2ecf20Sopenharmony_ci	irq_handler_t irqh;
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistruct sx8654 {
978c2ecf20Sopenharmony_ci	struct input_dev *input;
988c2ecf20Sopenharmony_ci	struct i2c_client *client;
998c2ecf20Sopenharmony_ci	struct gpio_desc *gpio_reset;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	spinlock_t lock;	/* for input reporting from irq/timer */
1028c2ecf20Sopenharmony_ci	struct timer_list timer;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	struct touchscreen_properties props;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	const struct sx865x_data *data;
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline void sx865x_penrelease(struct sx8654 *ts)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct input_dev *input_dev = ts->input;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	input_report_key(input_dev, BTN_TOUCH, 0);
1148c2ecf20Sopenharmony_ci	input_sync(input_dev);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void sx865x_penrelease_timer_handler(struct timer_list *t)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct sx8654 *ts = from_timer(ts, t, timer);
1208c2ecf20Sopenharmony_ci	unsigned long flags;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ts->lock, flags);
1238c2ecf20Sopenharmony_ci	sx865x_penrelease(ts);
1248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ts->lock, flags);
1258c2ecf20Sopenharmony_ci	dev_dbg(&ts->client->dev, "penrelease by timer\n");
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic irqreturn_t sx8650_irq(int irq, void *handle)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct sx8654 *ts = handle;
1318c2ecf20Sopenharmony_ci	struct device *dev = &ts->client->dev;
1328c2ecf20Sopenharmony_ci	int len, i;
1338c2ecf20Sopenharmony_ci	unsigned long flags;
1348c2ecf20Sopenharmony_ci	u8 stat;
1358c2ecf20Sopenharmony_ci	u16 x, y;
1368c2ecf20Sopenharmony_ci	u16 ch;
1378c2ecf20Sopenharmony_ci	u16 chdata;
1388c2ecf20Sopenharmony_ci	__be16 data[MAX_I2C_READ_LEN / sizeof(__be16)];
1398c2ecf20Sopenharmony_ci	u8 nchan = hweight32(ts->data->chan_mask);
1408c2ecf20Sopenharmony_ci	u8 readlen = nchan * sizeof(*data);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER
1438c2ecf20Sopenharmony_ci						    | I2C_REG_SX8650_STAT);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (!(stat & SX8650_STAT_CONVIRQ)) {
1468c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat);
1478c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	len = i2c_master_recv(ts->client, (u8 *)data, readlen);
1518c2ecf20Sopenharmony_ci	if (len != readlen) {
1528c2ecf20Sopenharmony_ci		dev_dbg(dev, "ignore short recv (%d)\n", len);
1538c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ts->lock, flags);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	x = 0;
1598c2ecf20Sopenharmony_ci	y = 0;
1608c2ecf20Sopenharmony_ci	for (i = 0; i < nchan; i++) {
1618c2ecf20Sopenharmony_ci		chdata = be16_to_cpu(data[i]);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		if (unlikely(chdata == 0xFFFF)) {
1648c2ecf20Sopenharmony_ci			dev_dbg(dev, "invalid qualified data @ %d\n", i);
1658c2ecf20Sopenharmony_ci			continue;
1668c2ecf20Sopenharmony_ci		} else if (unlikely(chdata & 0x8000)) {
1678c2ecf20Sopenharmony_ci			dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata);
1688c2ecf20Sopenharmony_ci			continue;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		ch = chdata >> 12;
1728c2ecf20Sopenharmony_ci		if (ch == CH_X)
1738c2ecf20Sopenharmony_ci			x = chdata & MAX_12BIT;
1748c2ecf20Sopenharmony_ci		else if (ch == CH_Y)
1758c2ecf20Sopenharmony_ci			y = chdata & MAX_12BIT;
1768c2ecf20Sopenharmony_ci		else
1778c2ecf20Sopenharmony_ci			dev_warn(dev, "unknown channel %d [0x%04x]\n", ch,
1788c2ecf20Sopenharmony_ci				 chdata);
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	touchscreen_report_pos(ts->input, &ts->props, x, y, false);
1828c2ecf20Sopenharmony_ci	input_report_key(ts->input, BTN_TOUCH, 1);
1838c2ecf20Sopenharmony_ci	input_sync(ts->input);
1848c2ecf20Sopenharmony_ci	dev_dbg(dev, "point(%4d,%4d)\n", x, y);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT);
1878c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ts->lock, flags);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic irqreturn_t sx8654_irq(int irq, void *handle)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct sx8654 *sx8654 = handle;
1958c2ecf20Sopenharmony_ci	int irqsrc;
1968c2ecf20Sopenharmony_ci	u8 data[4];
1978c2ecf20Sopenharmony_ci	unsigned int x, y;
1988c2ecf20Sopenharmony_ci	int retval;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	irqsrc = i2c_smbus_read_byte_data(sx8654->client,
2018c2ecf20Sopenharmony_ci					  CMD_READ_REGISTER | I2C_REG_IRQSRC);
2028c2ecf20Sopenharmony_ci	dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (irqsrc < 0)
2058c2ecf20Sopenharmony_ci		goto out;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (irqsrc & IRQ_PENRELEASE) {
2088c2ecf20Sopenharmony_ci		dev_dbg(&sx8654->client->dev, "pen release interrupt");
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		input_report_key(sx8654->input, BTN_TOUCH, 0);
2118c2ecf20Sopenharmony_ci		input_sync(sx8654->input);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
2158c2ecf20Sopenharmony_ci		dev_dbg(&sx8654->client->dev, "pen touch interrupt");
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		retval = i2c_master_recv(sx8654->client, data, sizeof(data));
2188c2ecf20Sopenharmony_ci		if (retval != sizeof(data))
2198c2ecf20Sopenharmony_ci			goto out;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		/* invalid data */
2228c2ecf20Sopenharmony_ci		if (unlikely(data[0] & 0x80 || data[2] & 0x80))
2238c2ecf20Sopenharmony_ci			goto out;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		x = ((data[0] & 0xf) << 8) | (data[1]);
2268c2ecf20Sopenharmony_ci		y = ((data[2] & 0xf) << 8) | (data[3]);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		touchscreen_report_pos(sx8654->input, &sx8654->props, x, y,
2298c2ecf20Sopenharmony_ci				       false);
2308c2ecf20Sopenharmony_ci		input_report_key(sx8654->input, BTN_TOUCH, 1);
2318c2ecf20Sopenharmony_ci		input_sync(sx8654->input);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ciout:
2378c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int sx8654_reset(struct sx8654 *ts)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	int err;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (ts->gpio_reset) {
2458c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(ts->gpio_reset, 1);
2468c2ecf20Sopenharmony_ci		udelay(2); /* Tpulse > 1µs */
2478c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(ts->gpio_reset, 0);
2488c2ecf20Sopenharmony_ci	} else {
2498c2ecf20Sopenharmony_ci		dev_dbg(&ts->client->dev, "NRST unavailable, try softreset\n");
2508c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte_data(ts->client, I2C_REG_SOFTRESET,
2518c2ecf20Sopenharmony_ci						SOFTRESET_VALUE);
2528c2ecf20Sopenharmony_ci		if (err)
2538c2ecf20Sopenharmony_ci			return err;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return 0;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int sx8654_open(struct input_dev *dev)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct sx8654 *sx8654 = input_get_drvdata(dev);
2628c2ecf20Sopenharmony_ci	struct i2c_client *client = sx8654->client;
2638c2ecf20Sopenharmony_ci	int error;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/* enable pen trigger mode */
2668c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
2678c2ecf20Sopenharmony_ci					  RATE_5000CPS | POWDLY_1_1MS);
2688c2ecf20Sopenharmony_ci	if (error) {
2698c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
2708c2ecf20Sopenharmony_ci		return error;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte(client, CMD_PENTRG);
2748c2ecf20Sopenharmony_ci	if (error) {
2758c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing command CMD_PENTRG failed");
2768c2ecf20Sopenharmony_ci		return error;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	enable_irq(client->irq);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return 0;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic void sx8654_close(struct input_dev *dev)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct sx8654 *sx8654 = input_get_drvdata(dev);
2878c2ecf20Sopenharmony_ci	struct i2c_client *client = sx8654->client;
2888c2ecf20Sopenharmony_ci	int error;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	disable_irq(client->irq);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (!sx8654->data->has_irq_penrelease)
2938c2ecf20Sopenharmony_ci		del_timer_sync(&sx8654->timer);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* enable manual mode mode */
2968c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
2978c2ecf20Sopenharmony_ci	if (error) {
2988c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing command CMD_MANUAL failed");
2998c2ecf20Sopenharmony_ci		return;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, RATE_MANUAL);
3038c2ecf20Sopenharmony_ci	if (error) {
3048c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
3058c2ecf20Sopenharmony_ci		return;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int sx8654_probe(struct i2c_client *client,
3108c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct sx8654 *sx8654;
3138c2ecf20Sopenharmony_ci	struct input_dev *input;
3148c2ecf20Sopenharmony_ci	int error;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
3178c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_READ_WORD_DATA))
3188c2ecf20Sopenharmony_ci		return -ENXIO;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
3218c2ecf20Sopenharmony_ci	if (!sx8654)
3228c2ecf20Sopenharmony_ci		return -ENOMEM;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
3258c2ecf20Sopenharmony_ci						     GPIOD_OUT_HIGH);
3268c2ecf20Sopenharmony_ci	if (IS_ERR(sx8654->gpio_reset)) {
3278c2ecf20Sopenharmony_ci		error = PTR_ERR(sx8654->gpio_reset);
3288c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
3298c2ecf20Sopenharmony_ci			dev_err(&client->dev, "unable to get reset-gpio: %d\n",
3308c2ecf20Sopenharmony_ci				error);
3318c2ecf20Sopenharmony_ci		return error;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "got GPIO reset pin\n");
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	sx8654->data = device_get_match_data(&client->dev);
3368c2ecf20Sopenharmony_ci	if (!sx8654->data)
3378c2ecf20Sopenharmony_ci		sx8654->data = (const struct sx865x_data *)id->driver_data;
3388c2ecf20Sopenharmony_ci	if (!sx8654->data) {
3398c2ecf20Sopenharmony_ci		dev_err(&client->dev, "invalid or missing device data\n");
3408c2ecf20Sopenharmony_ci		return -EINVAL;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!sx8654->data->has_irq_penrelease) {
3448c2ecf20Sopenharmony_ci		dev_dbg(&client->dev, "use timer for penrelease\n");
3458c2ecf20Sopenharmony_ci		timer_setup(&sx8654->timer, sx865x_penrelease_timer_handler, 0);
3468c2ecf20Sopenharmony_ci		spin_lock_init(&sx8654->lock);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	input = devm_input_allocate_device(&client->dev);
3508c2ecf20Sopenharmony_ci	if (!input)
3518c2ecf20Sopenharmony_ci		return -ENOMEM;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	input->name = "SX8654 I2C Touchscreen";
3548c2ecf20Sopenharmony_ci	input->id.bustype = BUS_I2C;
3558c2ecf20Sopenharmony_ci	input->dev.parent = &client->dev;
3568c2ecf20Sopenharmony_ci	input->open = sx8654_open;
3578c2ecf20Sopenharmony_ci	input->close = sx8654_close;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	__set_bit(INPUT_PROP_DIRECT, input->propbit);
3608c2ecf20Sopenharmony_ci	input_set_capability(input, EV_KEY, BTN_TOUCH);
3618c2ecf20Sopenharmony_ci	input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
3628c2ecf20Sopenharmony_ci	input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	touchscreen_parse_properties(input, false, &sx8654->props);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	sx8654->client = client;
3678c2ecf20Sopenharmony_ci	sx8654->input = input;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	input_set_drvdata(sx8654->input, sx8654);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	error = sx8654_reset(sx8654);
3728c2ecf20Sopenharmony_ci	if (error) {
3738c2ecf20Sopenharmony_ci		dev_err(&client->dev, "reset failed");
3748c2ecf20Sopenharmony_ci		return error;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
3788c2ecf20Sopenharmony_ci					  sx8654->data->chan_mask);
3798c2ecf20Sopenharmony_ci	if (error) {
3808c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
3818c2ecf20Sopenharmony_ci		return error;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (sx8654->data->has_reg_irqmask) {
3858c2ecf20Sopenharmony_ci		error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
3868c2ecf20Sopenharmony_ci						  IRQ_PENTOUCH_TOUCHCONVDONE |
3878c2ecf20Sopenharmony_ci							IRQ_PENRELEASE);
3888c2ecf20Sopenharmony_ci		if (error) {
3898c2ecf20Sopenharmony_ci			dev_err(&client->dev, "writing I2C_REG_IRQMASK failed");
3908c2ecf20Sopenharmony_ci			return error;
3918c2ecf20Sopenharmony_ci		}
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
3958c2ecf20Sopenharmony_ci					  CONDIRQ | RPDNT_100K | FILT_7SA);
3968c2ecf20Sopenharmony_ci	if (error) {
3978c2ecf20Sopenharmony_ci		dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
3988c2ecf20Sopenharmony_ci		return error;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	error = devm_request_threaded_irq(&client->dev, client->irq,
4028c2ecf20Sopenharmony_ci					  NULL, sx8654->data->irqh,
4038c2ecf20Sopenharmony_ci					  IRQF_ONESHOT,
4048c2ecf20Sopenharmony_ci					  client->name, sx8654);
4058c2ecf20Sopenharmony_ci	if (error) {
4068c2ecf20Sopenharmony_ci		dev_err(&client->dev,
4078c2ecf20Sopenharmony_ci			"Failed to enable IRQ %d, error: %d\n",
4088c2ecf20Sopenharmony_ci			client->irq, error);
4098c2ecf20Sopenharmony_ci		return error;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Disable the IRQ, we'll enable it in sx8654_open() */
4138c2ecf20Sopenharmony_ci	disable_irq(client->irq);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	error = input_register_device(sx8654->input);
4168c2ecf20Sopenharmony_ci	if (error)
4178c2ecf20Sopenharmony_ci		return error;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic const struct sx865x_data sx8650_data = {
4238c2ecf20Sopenharmony_ci	.cmd_manual		= 0xb0,
4248c2ecf20Sopenharmony_ci	.has_irq_penrelease	= false,
4258c2ecf20Sopenharmony_ci	.has_reg_irqmask	= false,
4268c2ecf20Sopenharmony_ci	.chan_mask		= (CONV_X | CONV_Y),
4278c2ecf20Sopenharmony_ci	.irqh			= sx8650_irq,
4288c2ecf20Sopenharmony_ci};
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic const struct sx865x_data sx8654_data = {
4318c2ecf20Sopenharmony_ci	.cmd_manual		= 0xc0,
4328c2ecf20Sopenharmony_ci	.has_irq_penrelease	= true,
4338c2ecf20Sopenharmony_ci	.has_reg_irqmask	= true,
4348c2ecf20Sopenharmony_ci	.chan_mask		= (CONV_X | CONV_Y),
4358c2ecf20Sopenharmony_ci	.irqh			= sx8654_irq,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
4398c2ecf20Sopenharmony_cistatic const struct of_device_id sx8654_of_match[] = {
4408c2ecf20Sopenharmony_ci	{
4418c2ecf20Sopenharmony_ci		.compatible = "semtech,sx8650",
4428c2ecf20Sopenharmony_ci		.data = &sx8650_data,
4438c2ecf20Sopenharmony_ci	}, {
4448c2ecf20Sopenharmony_ci		.compatible = "semtech,sx8654",
4458c2ecf20Sopenharmony_ci		.data = &sx8654_data,
4468c2ecf20Sopenharmony_ci	}, {
4478c2ecf20Sopenharmony_ci		.compatible = "semtech,sx8655",
4488c2ecf20Sopenharmony_ci		.data = &sx8654_data,
4498c2ecf20Sopenharmony_ci	}, {
4508c2ecf20Sopenharmony_ci		.compatible = "semtech,sx8656",
4518c2ecf20Sopenharmony_ci		.data = &sx8654_data,
4528c2ecf20Sopenharmony_ci	},
4538c2ecf20Sopenharmony_ci	{ }
4548c2ecf20Sopenharmony_ci};
4558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sx8654_of_match);
4568c2ecf20Sopenharmony_ci#endif
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic const struct i2c_device_id sx8654_id_table[] = {
4598c2ecf20Sopenharmony_ci	{ .name = "semtech_sx8650", .driver_data = (long)&sx8650_data },
4608c2ecf20Sopenharmony_ci	{ .name = "semtech_sx8654", .driver_data = (long)&sx8654_data },
4618c2ecf20Sopenharmony_ci	{ .name = "semtech_sx8655", .driver_data = (long)&sx8654_data },
4628c2ecf20Sopenharmony_ci	{ .name = "semtech_sx8656", .driver_data = (long)&sx8654_data },
4638c2ecf20Sopenharmony_ci	{ }
4648c2ecf20Sopenharmony_ci};
4658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sx8654_id_table);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic struct i2c_driver sx8654_driver = {
4688c2ecf20Sopenharmony_ci	.driver = {
4698c2ecf20Sopenharmony_ci		.name = "sx8654",
4708c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(sx8654_of_match),
4718c2ecf20Sopenharmony_ci	},
4728c2ecf20Sopenharmony_ci	.id_table = sx8654_id_table,
4738c2ecf20Sopenharmony_ci	.probe = sx8654_probe,
4748c2ecf20Sopenharmony_ci};
4758c2ecf20Sopenharmony_cimodule_i2c_driver(sx8654_driver);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
4788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
4798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
480