16d3a41abSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
243c4d13eSSimon Budig /*
343c4d13eSSimon Budig  * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
4fd335ab0SLothar Waßmann  * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
5dac90dc2SLothar Waßmann  * Lothar Waßmann <LW@KARO-electronics.de> (DT support)
6*9dfd9708SDario Binacchi  * Dario Binacchi <dario.binacchi@amarulasolutions.com> (regmap support)
743c4d13eSSimon Budig  */
843c4d13eSSimon Budig 
943c4d13eSSimon Budig /*
1043c4d13eSSimon Budig  * This is a driver for the EDT "Polytouch" family of touch controllers
1143c4d13eSSimon Budig  * based on the FocalTech FT5x06 line of chips.
1243c4d13eSSimon Budig  *
1343c4d13eSSimon Budig  * Development of this driver has been sponsored by Glyn:
1443c4d13eSSimon Budig  *    http://www.glyn.com/Products/Displays
1543c4d13eSSimon Budig  */
1643c4d13eSSimon Budig 
178726e4c9SMarco Felsch #include <linux/debugfs.h>
188726e4c9SMarco Felsch #include <linux/delay.h>
198726e4c9SMarco Felsch #include <linux/gpio/consumer.h>
208726e4c9SMarco Felsch #include <linux/i2c.h>
2143c4d13eSSimon Budig #include <linux/interrupt.h>
2243c4d13eSSimon Budig #include <linux/input.h>
2343c4d13eSSimon Budig #include <linux/input/mt.h>
242c005598SMaxime Ripard #include <linux/input/touchscreen.h>
258726e4c9SMarco Felsch #include <linux/irq.h>
268726e4c9SMarco Felsch #include <linux/kernel.h>
278726e4c9SMarco Felsch #include <linux/module.h>
285bcee83aSDario Binacchi #include <linux/property.h>
298726e4c9SMarco Felsch #include <linux/ratelimit.h>
30*9dfd9708SDario Binacchi #include <linux/regmap.h>
317448bfecSMylène Josserand #include <linux/regulator/consumer.h>
328726e4c9SMarco Felsch #include <linux/slab.h>
338726e4c9SMarco Felsch #include <linux/uaccess.h>
348726e4c9SMarco Felsch 
358726e4c9SMarco Felsch #include <asm/unaligned.h>
3643c4d13eSSimon Budig 
3743c4d13eSSimon Budig #define WORK_REGISTER_THRESHOLD		0x00
3843c4d13eSSimon Budig #define WORK_REGISTER_REPORT_RATE	0x08
3943c4d13eSSimon Budig #define WORK_REGISTER_GAIN		0x30
4043c4d13eSSimon Budig #define WORK_REGISTER_OFFSET		0x31
4143c4d13eSSimon Budig #define WORK_REGISTER_NUM_X		0x33
4243c4d13eSSimon Budig #define WORK_REGISTER_NUM_Y		0x34
4343c4d13eSSimon Budig 
4421d1611aSMarco Felsch #define PMOD_REGISTER_ACTIVE		0x00
4521d1611aSMarco Felsch #define PMOD_REGISTER_HIBERNATE		0x03
4621d1611aSMarco Felsch 
47fd335ab0SLothar Waßmann #define M09_REGISTER_THRESHOLD		0x80
48fd335ab0SLothar Waßmann #define M09_REGISTER_GAIN		0x92
49fd335ab0SLothar Waßmann #define M09_REGISTER_OFFSET		0x93
50fd335ab0SLothar Waßmann #define M09_REGISTER_NUM_X		0x94
51fd335ab0SLothar Waßmann #define M09_REGISTER_NUM_Y		0x95
52fd335ab0SLothar Waßmann 
5323ea98f4SDario Binacchi #define M12_REGISTER_REPORT_RATE	0x88
5423ea98f4SDario Binacchi 
55a2f39dacSMarco Felsch #define EV_REGISTER_THRESHOLD		0x40
56a2f39dacSMarco Felsch #define EV_REGISTER_GAIN		0x41
57b6eba860SMarco Felsch #define EV_REGISTER_OFFSET_Y		0x45
58b6eba860SMarco Felsch #define EV_REGISTER_OFFSET_X		0x46
59a2f39dacSMarco Felsch 
60fd335ab0SLothar Waßmann #define NO_REGISTER			0xff
61fd335ab0SLothar Waßmann 
6243c4d13eSSimon Budig #define WORK_REGISTER_OPMODE		0x3c
6343c4d13eSSimon Budig #define FACTORY_REGISTER_OPMODE		0x01
6421d1611aSMarco Felsch #define PMOD_REGISTER_OPMODE		0xa5
6543c4d13eSSimon Budig 
6643c4d13eSSimon Budig #define TOUCH_EVENT_DOWN		0x00
6743c4d13eSSimon Budig #define TOUCH_EVENT_UP			0x01
6843c4d13eSSimon Budig #define TOUCH_EVENT_ON			0x02
6943c4d13eSSimon Budig #define TOUCH_EVENT_RESERVED		0x03
7043c4d13eSSimon Budig 
7143c4d13eSSimon Budig #define EDT_NAME_LEN			23
7243c4d13eSSimon Budig #define EDT_SWITCH_MODE_RETRIES		10
7343c4d13eSSimon Budig #define EDT_SWITCH_MODE_DELAY		5 /* msec */
7443c4d13eSSimon Budig #define EDT_RAW_DATA_RETRIES		100
750eeecf60SAniroop Mathur #define EDT_RAW_DATA_DELAY		1000 /* usec */
7643c4d13eSSimon Budig 
7703161a95SDmitry Torokhov #define EDT_DEFAULT_NUM_X		1024
7803161a95SDmitry Torokhov #define EDT_DEFAULT_NUM_Y		1024
7903161a95SDmitry Torokhov 
8065c67985SDario Binacchi #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc)
8165c67985SDario Binacchi #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f)
8265c67985SDario Binacchi 
8321d1611aSMarco Felsch enum edt_pmode {
8421d1611aSMarco Felsch 	EDT_PMODE_NOT_SUPPORTED,
8521d1611aSMarco Felsch 	EDT_PMODE_HIBERNATE,
8621d1611aSMarco Felsch 	EDT_PMODE_POWEROFF,
8721d1611aSMarco Felsch };
8821d1611aSMarco Felsch 
89fd335ab0SLothar Waßmann enum edt_ver {
90169110c3SSimon Budig 	EDT_M06,
91169110c3SSimon Budig 	EDT_M09,
92aed5d0eeSSimon Budig 	EDT_M12,
93a2f39dacSMarco Felsch 	EV_FT,
94169110c3SSimon Budig 	GENERIC_FT,
95fd335ab0SLothar Waßmann };
96fd335ab0SLothar Waßmann 
97fd335ab0SLothar Waßmann struct edt_reg_addr {
98fd335ab0SLothar Waßmann 	int reg_threshold;
99fd335ab0SLothar Waßmann 	int reg_report_rate;
100fd335ab0SLothar Waßmann 	int reg_gain;
101fd335ab0SLothar Waßmann 	int reg_offset;
102b6eba860SMarco Felsch 	int reg_offset_x;
103b6eba860SMarco Felsch 	int reg_offset_y;
104fd335ab0SLothar Waßmann 	int reg_num_x;
105fd335ab0SLothar Waßmann 	int reg_num_y;
106fd335ab0SLothar Waßmann };
107fd335ab0SLothar Waßmann 
10843c4d13eSSimon Budig struct edt_ft5x06_ts_data {
10943c4d13eSSimon Budig 	struct i2c_client *client;
11043c4d13eSSimon Budig 	struct input_dev *input;
111ad368eb2SHans de Goede 	struct touchscreen_properties prop;
11243c4d13eSSimon Budig 	u16 num_x;
11343c4d13eSSimon Budig 	u16 num_y;
1147448bfecSMylène Josserand 	struct regulator *vcc;
115df4c40f4SStephan Gerhold 	struct regulator *iovcc;
11643c4d13eSSimon Budig 
11713c23cd1SFranklin S Cooper Jr 	struct gpio_desc *reset_gpio;
11813c23cd1SFranklin S Cooper Jr 	struct gpio_desc *wake_gpio;
119dac90dc2SLothar Waßmann 
120*9dfd9708SDario Binacchi 	struct regmap *regmap;
121*9dfd9708SDario Binacchi 
12243c4d13eSSimon Budig #if defined(CONFIG_DEBUG_FS)
12343c4d13eSSimon Budig 	struct dentry *debug_dir;
12443c4d13eSSimon Budig 	u8 *raw_buffer;
12543c4d13eSSimon Budig 	size_t raw_bufsize;
12643c4d13eSSimon Budig #endif
12743c4d13eSSimon Budig 
12843c4d13eSSimon Budig 	struct mutex mutex;
12943c4d13eSSimon Budig 	bool factory_mode;
13021d1611aSMarco Felsch 	enum edt_pmode suspend_mode;
13143c4d13eSSimon Budig 	int threshold;
13243c4d13eSSimon Budig 	int gain;
13343c4d13eSSimon Budig 	int offset;
134b6eba860SMarco Felsch 	int offset_x;
135b6eba860SMarco Felsch 	int offset_y;
13643c4d13eSSimon Budig 	int report_rate;
137b1d2a3ecSFranklin S Cooper Jr 	int max_support_points;
13843c4d13eSSimon Budig 
13943c4d13eSSimon Budig 	char name[EDT_NAME_LEN];
140480343dcSDario Binacchi 	char fw_version[EDT_NAME_LEN];
141fd335ab0SLothar Waßmann 
142fd335ab0SLothar Waßmann 	struct edt_reg_addr reg_addr;
143fd335ab0SLothar Waßmann 	enum edt_ver version;
144b777f93bSDario Binacchi 	unsigned int crc_errors;
145b777f93bSDario Binacchi 	unsigned int header_errors;
14643c4d13eSSimon Budig };
14743c4d13eSSimon Budig 
148b1d2a3ecSFranklin S Cooper Jr struct edt_i2c_chip_data {
149b1d2a3ecSFranklin S Cooper Jr 	int  max_support_points;
150b1d2a3ecSFranklin S Cooper Jr };
151b1d2a3ecSFranklin S Cooper Jr 
152*9dfd9708SDario Binacchi static const struct regmap_config edt_ft5x06_i2c_regmap_config = {
153*9dfd9708SDario Binacchi 	.reg_bits = 8,
154*9dfd9708SDario Binacchi 	.val_bits = 8,
155*9dfd9708SDario Binacchi };
15643c4d13eSSimon Budig 
15743c4d13eSSimon Budig static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
15843c4d13eSSimon Budig 				    u8 *buf, int buflen)
15943c4d13eSSimon Budig {
16043c4d13eSSimon Budig 	int i;
16143c4d13eSSimon Budig 	u8 crc = 0;
16243c4d13eSSimon Budig 
16343c4d13eSSimon Budig 	for (i = 0; i < buflen - 1; i++)
16443c4d13eSSimon Budig 		crc ^= buf[i];
16543c4d13eSSimon Budig 
16643c4d13eSSimon Budig 	if (crc != buf[buflen - 1]) {
167b777f93bSDario Binacchi 		tsdata->crc_errors++;
16843c4d13eSSimon Budig 		dev_err_ratelimited(&tsdata->client->dev,
16943c4d13eSSimon Budig 				    "crc error: 0x%02x expected, got 0x%02x\n",
17043c4d13eSSimon Budig 				    crc, buf[buflen - 1]);
17143c4d13eSSimon Budig 		return false;
17243c4d13eSSimon Budig 	}
17343c4d13eSSimon Budig 
17443c4d13eSSimon Budig 	return true;
17543c4d13eSSimon Budig }
17643c4d13eSSimon Budig 
177*9dfd9708SDario Binacchi static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size,
178*9dfd9708SDario Binacchi 			    void *val_buf, size_t val_size)
179*9dfd9708SDario Binacchi {
180*9dfd9708SDario Binacchi 	struct device *dev = context;
181*9dfd9708SDario Binacchi 	struct i2c_client *i2c = to_i2c_client(dev);
182*9dfd9708SDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c);
183*9dfd9708SDario Binacchi 	struct i2c_msg xfer[2];
184*9dfd9708SDario Binacchi 	bool reg_read = false;
185*9dfd9708SDario Binacchi 	u8 addr;
186*9dfd9708SDario Binacchi 	u8 wlen;
187*9dfd9708SDario Binacchi 	u8 wbuf[4], rbuf[3];
188*9dfd9708SDario Binacchi 	int ret;
189*9dfd9708SDario Binacchi 
190*9dfd9708SDario Binacchi 	addr = *((u8 *)reg_buf);
191*9dfd9708SDario Binacchi 	wbuf[0] = addr;
192*9dfd9708SDario Binacchi 	switch (addr) {
193*9dfd9708SDario Binacchi 	case 0xf5:
194*9dfd9708SDario Binacchi 		wlen = 3;
195*9dfd9708SDario Binacchi 		wbuf[0] = 0xf5;
196*9dfd9708SDario Binacchi 		wbuf[1] = 0xe;
197*9dfd9708SDario Binacchi 		wbuf[2] = *((u8 *)val_buf);
198*9dfd9708SDario Binacchi 		break;
199*9dfd9708SDario Binacchi 	case 0xf9:
200*9dfd9708SDario Binacchi 		wlen = 1;
201*9dfd9708SDario Binacchi 		break;
202*9dfd9708SDario Binacchi 	default:
203*9dfd9708SDario Binacchi 		wlen = 2;
204*9dfd9708SDario Binacchi 		reg_read = true;
205*9dfd9708SDario Binacchi 		wbuf[0] = M06_REG_CMD(tsdata->factory_mode);
206*9dfd9708SDario Binacchi 		wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr);
207*9dfd9708SDario Binacchi 		wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
208*9dfd9708SDario Binacchi 	}
209*9dfd9708SDario Binacchi 
210*9dfd9708SDario Binacchi 	xfer[0].addr  = i2c->addr;
211*9dfd9708SDario Binacchi 	xfer[0].flags = 0;
212*9dfd9708SDario Binacchi 	xfer[0].len = wlen;
213*9dfd9708SDario Binacchi 	xfer[0].buf = wbuf;
214*9dfd9708SDario Binacchi 
215*9dfd9708SDario Binacchi 	xfer[1].addr = i2c->addr;
216*9dfd9708SDario Binacchi 	xfer[1].flags = I2C_M_RD;
217*9dfd9708SDario Binacchi 	xfer[1].len = reg_read ? 2 : val_size;
218*9dfd9708SDario Binacchi 	xfer[1].buf = reg_read ? rbuf : val_buf;
219*9dfd9708SDario Binacchi 
220*9dfd9708SDario Binacchi 	ret = i2c_transfer(i2c->adapter, xfer, 2);
221*9dfd9708SDario Binacchi 	if (ret != 2) {
222*9dfd9708SDario Binacchi 		if (ret < 0)
223*9dfd9708SDario Binacchi 			return ret;
224*9dfd9708SDario Binacchi 
225*9dfd9708SDario Binacchi 		return -EIO;
226*9dfd9708SDario Binacchi 	}
227*9dfd9708SDario Binacchi 
228*9dfd9708SDario Binacchi 	if (addr == 0xf9) {
229*9dfd9708SDario Binacchi 		u8 *buf = (u8 *)val_buf;
230*9dfd9708SDario Binacchi 
231*9dfd9708SDario Binacchi 		if (buf[0] != 0xaa || buf[1] != 0xaa ||
232*9dfd9708SDario Binacchi 		    buf[2] != val_size) {
233*9dfd9708SDario Binacchi 			tsdata->header_errors++;
234*9dfd9708SDario Binacchi 			dev_err_ratelimited(dev,
235*9dfd9708SDario Binacchi 					    "Unexpected header: %02x%02x%02x\n",
236*9dfd9708SDario Binacchi 					    buf[0], buf[1], buf[2]);
237*9dfd9708SDario Binacchi 			return -EIO;
238*9dfd9708SDario Binacchi 		}
239*9dfd9708SDario Binacchi 
240*9dfd9708SDario Binacchi 		if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size))
241*9dfd9708SDario Binacchi 			return -EIO;
242*9dfd9708SDario Binacchi 	} else if (reg_read) {
243*9dfd9708SDario Binacchi 		u8 crc = wbuf[0] ^ wbuf[1] ^ rbuf[0];
244*9dfd9708SDario Binacchi 
245*9dfd9708SDario Binacchi 		if (crc != rbuf[1]) {
246*9dfd9708SDario Binacchi 			dev_err(dev, "crc error: 0x%02x expected, got 0x%02x\n",
247*9dfd9708SDario Binacchi 				crc, rbuf[1]);
248*9dfd9708SDario Binacchi 			return -EIO;
249*9dfd9708SDario Binacchi 		}
250*9dfd9708SDario Binacchi 
251*9dfd9708SDario Binacchi 		*((u8 *)val_buf) = rbuf[0];
252*9dfd9708SDario Binacchi 	}
253*9dfd9708SDario Binacchi 
254*9dfd9708SDario Binacchi 	return 0;
255*9dfd9708SDario Binacchi }
256*9dfd9708SDario Binacchi 
257*9dfd9708SDario Binacchi static int edt_M06_i2c_write(void *context, const void *data, size_t count)
258*9dfd9708SDario Binacchi {
259*9dfd9708SDario Binacchi 	struct device *dev = context;
260*9dfd9708SDario Binacchi 	struct i2c_client *i2c = to_i2c_client(dev);
261*9dfd9708SDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c);
262*9dfd9708SDario Binacchi 	u8 addr, val;
263*9dfd9708SDario Binacchi 	u8 wbuf[4];
264*9dfd9708SDario Binacchi 	struct i2c_msg xfer;
265*9dfd9708SDario Binacchi 	int ret;
266*9dfd9708SDario Binacchi 
267*9dfd9708SDario Binacchi 	addr = *((u8 *)data);
268*9dfd9708SDario Binacchi 	val = *((u8 *)data + 1);
269*9dfd9708SDario Binacchi 
270*9dfd9708SDario Binacchi 	wbuf[0] = M06_REG_CMD(tsdata->factory_mode);
271*9dfd9708SDario Binacchi 	wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr);
272*9dfd9708SDario Binacchi 	wbuf[2] = val;
273*9dfd9708SDario Binacchi 	wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2];
274*9dfd9708SDario Binacchi 
275*9dfd9708SDario Binacchi 	xfer.addr  = i2c->addr;
276*9dfd9708SDario Binacchi 	xfer.flags = 0;
277*9dfd9708SDario Binacchi 	xfer.len = 4;
278*9dfd9708SDario Binacchi 	xfer.buf = wbuf;
279*9dfd9708SDario Binacchi 
280*9dfd9708SDario Binacchi 	ret = i2c_transfer(i2c->adapter, &xfer, 1);
281*9dfd9708SDario Binacchi 	if (ret != 1) {
282*9dfd9708SDario Binacchi 		if (ret < 0)
283*9dfd9708SDario Binacchi 			return ret;
284*9dfd9708SDario Binacchi 
285*9dfd9708SDario Binacchi 		return -EIO;
286*9dfd9708SDario Binacchi 	}
287*9dfd9708SDario Binacchi 
288*9dfd9708SDario Binacchi 	return 0;
289*9dfd9708SDario Binacchi }
290*9dfd9708SDario Binacchi 
291*9dfd9708SDario Binacchi static const struct regmap_config edt_M06_i2c_regmap_config = {
292*9dfd9708SDario Binacchi 	.reg_bits = 8,
293*9dfd9708SDario Binacchi 	.val_bits = 8,
294*9dfd9708SDario Binacchi 	.read = edt_M06_i2c_read,
295*9dfd9708SDario Binacchi 	.write = edt_M06_i2c_write,
296*9dfd9708SDario Binacchi };
297*9dfd9708SDario Binacchi 
29843c4d13eSSimon Budig static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
29943c4d13eSSimon Budig {
30043c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = dev_id;
30143c4d13eSSimon Budig 	struct device *dev = &tsdata->client->dev;
302fd335ab0SLothar Waßmann 	u8 cmd;
3039378c025SFranklin S Cooper Jr 	u8 rdbuf[63];
30443c4d13eSSimon Budig 	int i, type, x, y, id;
305c789f1fbSFranklin S Cooper Jr 	int offset, tplen, datalen, crclen;
30643c4d13eSSimon Budig 	int error;
30743c4d13eSSimon Budig 
308fd335ab0SLothar Waßmann 	switch (tsdata->version) {
309169110c3SSimon Budig 	case EDT_M06:
310fd335ab0SLothar Waßmann 		cmd = 0xf9; /* tell the controller to send touch data */
311fd335ab0SLothar Waßmann 		offset = 5; /* where the actual touch data starts */
312fd335ab0SLothar Waßmann 		tplen = 4;  /* data comes in so called frames */
313c789f1fbSFranklin S Cooper Jr 		crclen = 1; /* length of the crc data */
314fd335ab0SLothar Waßmann 		break;
315fd335ab0SLothar Waßmann 
316169110c3SSimon Budig 	case EDT_M09:
317aed5d0eeSSimon Budig 	case EDT_M12:
318a2f39dacSMarco Felsch 	case EV_FT:
319169110c3SSimon Budig 	case GENERIC_FT:
3209378c025SFranklin S Cooper Jr 		cmd = 0x0;
3219378c025SFranklin S Cooper Jr 		offset = 3;
322fd335ab0SLothar Waßmann 		tplen = 6;
323c789f1fbSFranklin S Cooper Jr 		crclen = 0;
324fd335ab0SLothar Waßmann 		break;
325fd335ab0SLothar Waßmann 
326fd335ab0SLothar Waßmann 	default:
327fd335ab0SLothar Waßmann 		goto out;
328fd335ab0SLothar Waßmann 	}
329fd335ab0SLothar Waßmann 
33043c4d13eSSimon Budig 	memset(rdbuf, 0, sizeof(rdbuf));
331b1d2a3ecSFranklin S Cooper Jr 	datalen = tplen * tsdata->max_support_points + offset + crclen;
33243c4d13eSSimon Budig 
333*9dfd9708SDario Binacchi 	error = regmap_bulk_read(tsdata->regmap, cmd, rdbuf, datalen);
33443c4d13eSSimon Budig 	if (error) {
33543c4d13eSSimon Budig 		dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
33643c4d13eSSimon Budig 				    error);
33743c4d13eSSimon Budig 		goto out;
33843c4d13eSSimon Budig 	}
33943c4d13eSSimon Budig 
340b1d2a3ecSFranklin S Cooper Jr 	for (i = 0; i < tsdata->max_support_points; i++) {
341fd335ab0SLothar Waßmann 		u8 *buf = &rdbuf[i * tplen + offset];
34243c4d13eSSimon Budig 
34343c4d13eSSimon Budig 		type = buf[0] >> 6;
34443c4d13eSSimon Budig 		/* ignore Reserved events */
34543c4d13eSSimon Budig 		if (type == TOUCH_EVENT_RESERVED)
34643c4d13eSSimon Budig 			continue;
34743c4d13eSSimon Budig 
348fd335ab0SLothar Waßmann 		/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
349169110c3SSimon Budig 		if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
350ee3e946eSLothar Waßmann 			continue;
351ee3e946eSLothar Waßmann 
3521b9c698cSDmitry Torokhov 		x = get_unaligned_be16(buf) & 0x0fff;
3531b9c698cSDmitry Torokhov 		y = get_unaligned_be16(buf + 2) & 0x0fff;
354a2f39dacSMarco Felsch 		/* The FT5x26 send the y coordinate first */
355a2f39dacSMarco Felsch 		if (tsdata->version == EV_FT)
356a2f39dacSMarco Felsch 			swap(x, y);
357a2f39dacSMarco Felsch 
35843c4d13eSSimon Budig 		id = (buf[2] >> 4) & 0x0f;
35943c4d13eSSimon Budig 
36043c4d13eSSimon Budig 		input_mt_slot(tsdata->input, id);
36117b92927SDmitry Torokhov 		if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
36217b92927SDmitry Torokhov 					       type != TOUCH_EVENT_UP))
36317b92927SDmitry Torokhov 			touchscreen_report_pos(tsdata->input, &tsdata->prop,
36417b92927SDmitry Torokhov 					       x, y, true);
36543c4d13eSSimon Budig 	}
36643c4d13eSSimon Budig 
36743c4d13eSSimon Budig 	input_mt_report_pointer_emulation(tsdata->input, true);
36843c4d13eSSimon Budig 	input_sync(tsdata->input);
36943c4d13eSSimon Budig 
37043c4d13eSSimon Budig out:
37143c4d13eSSimon Budig 	return IRQ_HANDLED;
37243c4d13eSSimon Budig }
37343c4d13eSSimon Budig 
37443c4d13eSSimon Budig struct edt_ft5x06_attribute {
37543c4d13eSSimon Budig 	struct device_attribute dattr;
37643c4d13eSSimon Budig 	size_t field_offset;
37743c4d13eSSimon Budig 	u8 limit_low;
37843c4d13eSSimon Budig 	u8 limit_high;
379fd335ab0SLothar Waßmann 	u8 addr_m06;
380fd335ab0SLothar Waßmann 	u8 addr_m09;
3812ebc1919SMarco Felsch 	u8 addr_ev;
38243c4d13eSSimon Budig };
38343c4d13eSSimon Budig 
3842ebc1919SMarco Felsch #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev,		\
385fd335ab0SLothar Waßmann 		_limit_low, _limit_high)				\
38643c4d13eSSimon Budig 	struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = {	\
38743c4d13eSSimon Budig 		.dattr = __ATTR(_field, _mode,				\
38843c4d13eSSimon Budig 				edt_ft5x06_setting_show,		\
38943c4d13eSSimon Budig 				edt_ft5x06_setting_store),		\
390fd335ab0SLothar Waßmann 		.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
391fd335ab0SLothar Waßmann 		.addr_m06 = _addr_m06,					\
392fd335ab0SLothar Waßmann 		.addr_m09 = _addr_m09,					\
3932ebc1919SMarco Felsch 		.addr_ev  = _addr_ev,					\
39443c4d13eSSimon Budig 		.limit_low = _limit_low,				\
39543c4d13eSSimon Budig 		.limit_high = _limit_high,				\
39643c4d13eSSimon Budig 	}
39743c4d13eSSimon Budig 
39843c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_show(struct device *dev,
39943c4d13eSSimon Budig 				       struct device_attribute *dattr,
40043c4d13eSSimon Budig 				       char *buf)
40143c4d13eSSimon Budig {
40243c4d13eSSimon Budig 	struct i2c_client *client = to_i2c_client(dev);
40343c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
40443c4d13eSSimon Budig 	struct edt_ft5x06_attribute *attr =
40543c4d13eSSimon Budig 			container_of(dattr, struct edt_ft5x06_attribute, dattr);
4061730d814SLothar Waßmann 	u8 *field = (u8 *)tsdata + attr->field_offset;
407*9dfd9708SDario Binacchi 	unsigned int val;
40843c4d13eSSimon Budig 	size_t count = 0;
40943c4d13eSSimon Budig 	int error = 0;
410fd335ab0SLothar Waßmann 	u8 addr;
41143c4d13eSSimon Budig 
41243c4d13eSSimon Budig 	mutex_lock(&tsdata->mutex);
41343c4d13eSSimon Budig 
41443c4d13eSSimon Budig 	if (tsdata->factory_mode) {
41543c4d13eSSimon Budig 		error = -EIO;
41643c4d13eSSimon Budig 		goto out;
41743c4d13eSSimon Budig 	}
41843c4d13eSSimon Budig 
419fd335ab0SLothar Waßmann 	switch (tsdata->version) {
420169110c3SSimon Budig 	case EDT_M06:
421fd335ab0SLothar Waßmann 		addr = attr->addr_m06;
422fd335ab0SLothar Waßmann 		break;
423fd335ab0SLothar Waßmann 
424169110c3SSimon Budig 	case EDT_M09:
425aed5d0eeSSimon Budig 	case EDT_M12:
426169110c3SSimon Budig 	case GENERIC_FT:
427fd335ab0SLothar Waßmann 		addr = attr->addr_m09;
428fd335ab0SLothar Waßmann 		break;
429fd335ab0SLothar Waßmann 
4302ebc1919SMarco Felsch 	case EV_FT:
4312ebc1919SMarco Felsch 		addr = attr->addr_ev;
4322ebc1919SMarco Felsch 		break;
4332ebc1919SMarco Felsch 
434fd335ab0SLothar Waßmann 	default:
435fd335ab0SLothar Waßmann 		error = -ENODEV;
436fd335ab0SLothar Waßmann 		goto out;
437fd335ab0SLothar Waßmann 	}
438fd335ab0SLothar Waßmann 
439fd335ab0SLothar Waßmann 	if (addr != NO_REGISTER) {
440*9dfd9708SDario Binacchi 		error = regmap_read(tsdata->regmap, addr, &val);
441*9dfd9708SDario Binacchi 		if (error) {
44243c4d13eSSimon Budig 			dev_err(&tsdata->client->dev,
44343c4d13eSSimon Budig 				"Failed to fetch attribute %s, error %d\n",
44443c4d13eSSimon Budig 				dattr->attr.name, error);
44543c4d13eSSimon Budig 			goto out;
44643c4d13eSSimon Budig 		}
447fd335ab0SLothar Waßmann 	} else {
448fd335ab0SLothar Waßmann 		val = *field;
449fd335ab0SLothar Waßmann 	}
45043c4d13eSSimon Budig 
45143c4d13eSSimon Budig 	if (val != *field) {
45243c4d13eSSimon Budig 		dev_warn(&tsdata->client->dev,
45343c4d13eSSimon Budig 			 "%s: read (%d) and stored value (%d) differ\n",
45443c4d13eSSimon Budig 			 dattr->attr.name, val, *field);
45543c4d13eSSimon Budig 		*field = val;
45643c4d13eSSimon Budig 	}
45743c4d13eSSimon Budig 
45843c4d13eSSimon Budig 	count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
45943c4d13eSSimon Budig out:
46043c4d13eSSimon Budig 	mutex_unlock(&tsdata->mutex);
46143c4d13eSSimon Budig 	return error ?: count;
46243c4d13eSSimon Budig }
46343c4d13eSSimon Budig 
46443c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_store(struct device *dev,
46543c4d13eSSimon Budig 					struct device_attribute *dattr,
46643c4d13eSSimon Budig 					const char *buf, size_t count)
46743c4d13eSSimon Budig {
46843c4d13eSSimon Budig 	struct i2c_client *client = to_i2c_client(dev);
46943c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
47043c4d13eSSimon Budig 	struct edt_ft5x06_attribute *attr =
47143c4d13eSSimon Budig 			container_of(dattr, struct edt_ft5x06_attribute, dattr);
4721730d814SLothar Waßmann 	u8 *field = (u8 *)tsdata + attr->field_offset;
47343c4d13eSSimon Budig 	unsigned int val;
47443c4d13eSSimon Budig 	int error;
475fd335ab0SLothar Waßmann 	u8 addr;
47643c4d13eSSimon Budig 
47743c4d13eSSimon Budig 	mutex_lock(&tsdata->mutex);
47843c4d13eSSimon Budig 
47943c4d13eSSimon Budig 	if (tsdata->factory_mode) {
48043c4d13eSSimon Budig 		error = -EIO;
48143c4d13eSSimon Budig 		goto out;
48243c4d13eSSimon Budig 	}
48343c4d13eSSimon Budig 
48443c4d13eSSimon Budig 	error = kstrtouint(buf, 0, &val);
48543c4d13eSSimon Budig 	if (error)
48643c4d13eSSimon Budig 		goto out;
48743c4d13eSSimon Budig 
48843c4d13eSSimon Budig 	if (val < attr->limit_low || val > attr->limit_high) {
48943c4d13eSSimon Budig 		error = -ERANGE;
49043c4d13eSSimon Budig 		goto out;
49143c4d13eSSimon Budig 	}
49243c4d13eSSimon Budig 
493fd335ab0SLothar Waßmann 	switch (tsdata->version) {
494169110c3SSimon Budig 	case EDT_M06:
495fd335ab0SLothar Waßmann 		addr = attr->addr_m06;
496fd335ab0SLothar Waßmann 		break;
497fd335ab0SLothar Waßmann 
498169110c3SSimon Budig 	case EDT_M09:
499aed5d0eeSSimon Budig 	case EDT_M12:
500169110c3SSimon Budig 	case GENERIC_FT:
501fd335ab0SLothar Waßmann 		addr = attr->addr_m09;
502fd335ab0SLothar Waßmann 		break;
503fd335ab0SLothar Waßmann 
5042ebc1919SMarco Felsch 	case EV_FT:
5052ebc1919SMarco Felsch 		addr = attr->addr_ev;
5062ebc1919SMarco Felsch 		break;
5072ebc1919SMarco Felsch 
508fd335ab0SLothar Waßmann 	default:
509fd335ab0SLothar Waßmann 		error = -ENODEV;
510fd335ab0SLothar Waßmann 		goto out;
511fd335ab0SLothar Waßmann 	}
512fd335ab0SLothar Waßmann 
513fd335ab0SLothar Waßmann 	if (addr != NO_REGISTER) {
514*9dfd9708SDario Binacchi 		error = regmap_write(tsdata->regmap, addr, val);
51543c4d13eSSimon Budig 		if (error) {
51643c4d13eSSimon Budig 			dev_err(&tsdata->client->dev,
51743c4d13eSSimon Budig 				"Failed to update attribute %s, error: %d\n",
51843c4d13eSSimon Budig 				dattr->attr.name, error);
51943c4d13eSSimon Budig 			goto out;
52043c4d13eSSimon Budig 		}
521fd335ab0SLothar Waßmann 	}
52243c4d13eSSimon Budig 	*field = val;
52343c4d13eSSimon Budig 
52443c4d13eSSimon Budig out:
52543c4d13eSSimon Budig 	mutex_unlock(&tsdata->mutex);
52643c4d13eSSimon Budig 	return error ?: count;
52743c4d13eSSimon Budig }
52843c4d13eSSimon Budig 
529aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-5 */
530fd335ab0SLothar Waßmann static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
5312ebc1919SMarco Felsch 		M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31);
532aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-16 */
533fd335ab0SLothar Waßmann static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
5342ebc1919SMarco Felsch 		M09_REGISTER_OFFSET, NO_REGISTER, 0, 31);
535b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */
536b6eba860SMarco Felsch static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
537b6eba860SMarco Felsch 		EV_REGISTER_OFFSET_X, 0, 80);
538b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */
539b6eba860SMarco Felsch static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
540b6eba860SMarco Felsch 		EV_REGISTER_OFFSET_Y, 0, 80);
541aed5d0eeSSimon Budig /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
542fd335ab0SLothar Waßmann static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
5432ebc1919SMarco Felsch 		M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255);
54423ea98f4SDario Binacchi /* m06: range 3 to 14, m12: range 1 to 255 */
545fd335ab0SLothar Waßmann static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
54623ea98f4SDario Binacchi 		M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255);
54743c4d13eSSimon Budig 
54860790a58SDario Binacchi static ssize_t model_show(struct device *dev, struct device_attribute *attr,
54960790a58SDario Binacchi 			  char *buf)
55060790a58SDario Binacchi {
55160790a58SDario Binacchi 	struct i2c_client *client = to_i2c_client(dev);
55260790a58SDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
55360790a58SDario Binacchi 
55460790a58SDario Binacchi 	return sysfs_emit(buf, "%s\n", tsdata->name);
55560790a58SDario Binacchi }
55660790a58SDario Binacchi 
55760790a58SDario Binacchi static DEVICE_ATTR_RO(model);
55860790a58SDario Binacchi 
559480343dcSDario Binacchi static ssize_t fw_version_show(struct device *dev,
560480343dcSDario Binacchi 			       struct device_attribute *attr, char *buf)
561480343dcSDario Binacchi {
562480343dcSDario Binacchi 	struct i2c_client *client = to_i2c_client(dev);
563480343dcSDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
564480343dcSDario Binacchi 
565480343dcSDario Binacchi 	return sysfs_emit(buf, "%s\n", tsdata->fw_version);
566480343dcSDario Binacchi }
567480343dcSDario Binacchi 
568480343dcSDario Binacchi static DEVICE_ATTR_RO(fw_version);
569480343dcSDario Binacchi 
570b777f93bSDario Binacchi /* m06 only */
571b777f93bSDario Binacchi static ssize_t header_errors_show(struct device *dev,
572b777f93bSDario Binacchi 				  struct device_attribute *attr, char *buf)
573b777f93bSDario Binacchi {
574b777f93bSDario Binacchi 	struct i2c_client *client = to_i2c_client(dev);
575b777f93bSDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
576b777f93bSDario Binacchi 
577b777f93bSDario Binacchi 	return sysfs_emit(buf, "%d\n", tsdata->header_errors);
578b777f93bSDario Binacchi }
579b777f93bSDario Binacchi 
580b777f93bSDario Binacchi static DEVICE_ATTR_RO(header_errors);
581b777f93bSDario Binacchi 
582b777f93bSDario Binacchi /* m06 only */
583b777f93bSDario Binacchi static ssize_t crc_errors_show(struct device *dev,
584b777f93bSDario Binacchi 			       struct device_attribute *attr, char *buf)
585b777f93bSDario Binacchi {
586b777f93bSDario Binacchi 	struct i2c_client *client = to_i2c_client(dev);
587b777f93bSDario Binacchi 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
588b777f93bSDario Binacchi 
589b777f93bSDario Binacchi 	return sysfs_emit(buf, "%d\n", tsdata->crc_errors);
590b777f93bSDario Binacchi }
591b777f93bSDario Binacchi 
592b777f93bSDario Binacchi static DEVICE_ATTR_RO(crc_errors);
593b777f93bSDario Binacchi 
59443c4d13eSSimon Budig static struct attribute *edt_ft5x06_attrs[] = {
59543c4d13eSSimon Budig 	&edt_ft5x06_attr_gain.dattr.attr,
59643c4d13eSSimon Budig 	&edt_ft5x06_attr_offset.dattr.attr,
597b6eba860SMarco Felsch 	&edt_ft5x06_attr_offset_x.dattr.attr,
598b6eba860SMarco Felsch 	&edt_ft5x06_attr_offset_y.dattr.attr,
59943c4d13eSSimon Budig 	&edt_ft5x06_attr_threshold.dattr.attr,
60043c4d13eSSimon Budig 	&edt_ft5x06_attr_report_rate.dattr.attr,
60160790a58SDario Binacchi 	&dev_attr_model.attr,
602480343dcSDario Binacchi 	&dev_attr_fw_version.attr,
603b777f93bSDario Binacchi 	&dev_attr_header_errors.attr,
604b777f93bSDario Binacchi 	&dev_attr_crc_errors.attr,
60543c4d13eSSimon Budig 	NULL
60643c4d13eSSimon Budig };
60743c4d13eSSimon Budig 
60843c4d13eSSimon Budig static const struct attribute_group edt_ft5x06_attr_group = {
60943c4d13eSSimon Budig 	.attrs = edt_ft5x06_attrs,
61043c4d13eSSimon Budig };
61143c4d13eSSimon Budig 
612f4ee52f3SMarco Felsch static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata)
613f4ee52f3SMarco Felsch {
614f4ee52f3SMarco Felsch 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
615*9dfd9708SDario Binacchi 	struct regmap *regmap = tsdata->regmap;
616f4ee52f3SMarco Felsch 
617*9dfd9708SDario Binacchi 	regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold);
618*9dfd9708SDario Binacchi 	regmap_write(regmap, reg_addr->reg_gain, tsdata->gain);
619f4ee52f3SMarco Felsch 	if (reg_addr->reg_offset != NO_REGISTER)
620*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_offset, tsdata->offset);
621f4ee52f3SMarco Felsch 	if (reg_addr->reg_offset_x != NO_REGISTER)
622*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x);
623f4ee52f3SMarco Felsch 	if (reg_addr->reg_offset_y != NO_REGISTER)
624*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y);
625f4ee52f3SMarco Felsch 	if (reg_addr->reg_report_rate != NO_REGISTER)
626*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_report_rate,
627f4ee52f3SMarco Felsch 			     tsdata->report_rate);
628f4ee52f3SMarco Felsch }
629f4ee52f3SMarco Felsch 
63043c4d13eSSimon Budig #ifdef CONFIG_DEBUG_FS
63143c4d13eSSimon Budig static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
63243c4d13eSSimon Budig {
63343c4d13eSSimon Budig 	struct i2c_client *client = tsdata->client;
63443c4d13eSSimon Budig 	int retries = EDT_SWITCH_MODE_RETRIES;
635*9dfd9708SDario Binacchi 	unsigned int val;
63643c4d13eSSimon Budig 	int error;
63743c4d13eSSimon Budig 
6384b3e910dSDmitry Torokhov 	if (tsdata->version != EDT_M06) {
6394b3e910dSDmitry Torokhov 		dev_err(&client->dev,
6404b3e910dSDmitry Torokhov 			"No factory mode support for non-M06 devices\n");
6414b3e910dSDmitry Torokhov 		return -EINVAL;
6424b3e910dSDmitry Torokhov 	}
6434b3e910dSDmitry Torokhov 
64443c4d13eSSimon Budig 	disable_irq(client->irq);
64543c4d13eSSimon Budig 
64643c4d13eSSimon Budig 	if (!tsdata->raw_buffer) {
64743c4d13eSSimon Budig 		tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y *
64843c4d13eSSimon Budig 				      sizeof(u16);
64943c4d13eSSimon Budig 		tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL);
65043c4d13eSSimon Budig 		if (!tsdata->raw_buffer) {
65143c4d13eSSimon Budig 			error = -ENOMEM;
65243c4d13eSSimon Budig 			goto err_out;
65343c4d13eSSimon Budig 		}
65443c4d13eSSimon Budig 	}
65543c4d13eSSimon Budig 
65643c4d13eSSimon Budig 	/* mode register is 0x3c when in the work mode */
657*9dfd9708SDario Binacchi 	error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03);
65843c4d13eSSimon Budig 	if (error) {
65943c4d13eSSimon Budig 		dev_err(&client->dev,
66043c4d13eSSimon Budig 			"failed to switch to factory mode, error %d\n", error);
66143c4d13eSSimon Budig 		goto err_out;
66243c4d13eSSimon Budig 	}
66343c4d13eSSimon Budig 
66443c4d13eSSimon Budig 	tsdata->factory_mode = true;
66543c4d13eSSimon Budig 	do {
66643c4d13eSSimon Budig 		mdelay(EDT_SWITCH_MODE_DELAY);
66743c4d13eSSimon Budig 		/* mode register is 0x01 when in factory mode */
668*9dfd9708SDario Binacchi 		error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE,
669*9dfd9708SDario Binacchi 				    &val);
670*9dfd9708SDario Binacchi 		if (!error && val == 0x03)
67143c4d13eSSimon Budig 			break;
67243c4d13eSSimon Budig 	} while (--retries > 0);
67343c4d13eSSimon Budig 
67443c4d13eSSimon Budig 	if (retries == 0) {
67543c4d13eSSimon Budig 		dev_err(&client->dev, "not in factory mode after %dms.\n",
67643c4d13eSSimon Budig 			EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
67743c4d13eSSimon Budig 		error = -EIO;
67843c4d13eSSimon Budig 		goto err_out;
67943c4d13eSSimon Budig 	}
68043c4d13eSSimon Budig 
68143c4d13eSSimon Budig 	return 0;
68243c4d13eSSimon Budig 
68343c4d13eSSimon Budig err_out:
68443c4d13eSSimon Budig 	kfree(tsdata->raw_buffer);
68543c4d13eSSimon Budig 	tsdata->raw_buffer = NULL;
68643c4d13eSSimon Budig 	tsdata->factory_mode = false;
68743c4d13eSSimon Budig 	enable_irq(client->irq);
68843c4d13eSSimon Budig 
68943c4d13eSSimon Budig 	return error;
69043c4d13eSSimon Budig }
69143c4d13eSSimon Budig 
69243c4d13eSSimon Budig static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
69343c4d13eSSimon Budig {
69443c4d13eSSimon Budig 	struct i2c_client *client = tsdata->client;
69543c4d13eSSimon Budig 	int retries = EDT_SWITCH_MODE_RETRIES;
696*9dfd9708SDario Binacchi 	unsigned int val;
69743c4d13eSSimon Budig 	int error;
69843c4d13eSSimon Budig 
69943c4d13eSSimon Budig 	/* mode register is 0x01 when in the factory mode */
700*9dfd9708SDario Binacchi 	error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1);
70143c4d13eSSimon Budig 	if (error) {
70243c4d13eSSimon Budig 		dev_err(&client->dev,
70343c4d13eSSimon Budig 			"failed to switch to work mode, error: %d\n", error);
70443c4d13eSSimon Budig 		return error;
70543c4d13eSSimon Budig 	}
70643c4d13eSSimon Budig 
70743c4d13eSSimon Budig 	tsdata->factory_mode = false;
70843c4d13eSSimon Budig 
70943c4d13eSSimon Budig 	do {
71043c4d13eSSimon Budig 		mdelay(EDT_SWITCH_MODE_DELAY);
71143c4d13eSSimon Budig 		/* mode register is 0x01 when in factory mode */
712*9dfd9708SDario Binacchi 		error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val);
713*9dfd9708SDario Binacchi 		if (!error && val == 0x01)
71443c4d13eSSimon Budig 			break;
71543c4d13eSSimon Budig 	} while (--retries > 0);
71643c4d13eSSimon Budig 
71743c4d13eSSimon Budig 	if (retries == 0) {
71843c4d13eSSimon Budig 		dev_err(&client->dev, "not in work mode after %dms.\n",
71943c4d13eSSimon Budig 			EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
72043c4d13eSSimon Budig 		tsdata->factory_mode = true;
72143c4d13eSSimon Budig 		return -EIO;
72243c4d13eSSimon Budig 	}
72343c4d13eSSimon Budig 
72443c4d13eSSimon Budig 	kfree(tsdata->raw_buffer);
72543c4d13eSSimon Budig 	tsdata->raw_buffer = NULL;
72643c4d13eSSimon Budig 
727f4ee52f3SMarco Felsch 	edt_ft5x06_restore_reg_parameters(tsdata);
72843c4d13eSSimon Budig 	enable_irq(client->irq);
72943c4d13eSSimon Budig 
73043c4d13eSSimon Budig 	return 0;
73143c4d13eSSimon Budig }
73243c4d13eSSimon Budig 
73343c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode)
73443c4d13eSSimon Budig {
73543c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = data;
73643c4d13eSSimon Budig 
73743c4d13eSSimon Budig 	*mode = tsdata->factory_mode;
73843c4d13eSSimon Budig 
73943c4d13eSSimon Budig 	return 0;
74043c4d13eSSimon Budig };
74143c4d13eSSimon Budig 
74243c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
74343c4d13eSSimon Budig {
74443c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = data;
74543c4d13eSSimon Budig 	int retval = 0;
74643c4d13eSSimon Budig 
74743c4d13eSSimon Budig 	if (mode > 1)
74843c4d13eSSimon Budig 		return -ERANGE;
74943c4d13eSSimon Budig 
75043c4d13eSSimon Budig 	mutex_lock(&tsdata->mutex);
75143c4d13eSSimon Budig 
75243c4d13eSSimon Budig 	if (mode != tsdata->factory_mode) {
75343c4d13eSSimon Budig 		retval = mode ? edt_ft5x06_factory_mode(tsdata) :
75443c4d13eSSimon Budig 				edt_ft5x06_work_mode(tsdata);
75543c4d13eSSimon Budig 	}
75643c4d13eSSimon Budig 
75743c4d13eSSimon Budig 	mutex_unlock(&tsdata->mutex);
75843c4d13eSSimon Budig 
75943c4d13eSSimon Budig 	return retval;
76043c4d13eSSimon Budig };
76143c4d13eSSimon Budig 
76243c4d13eSSimon Budig DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
76343c4d13eSSimon Budig 			edt_ft5x06_debugfs_mode_set, "%llu\n");
76443c4d13eSSimon Budig 
76543c4d13eSSimon Budig static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
766d19ec82cSDario Binacchi 						char __user *buf, size_t count,
767d19ec82cSDario Binacchi 						loff_t *off)
76843c4d13eSSimon Budig {
76943c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = file->private_data;
77043c4d13eSSimon Budig 	struct i2c_client *client = tsdata->client;
77143c4d13eSSimon Budig 	int retries  = EDT_RAW_DATA_RETRIES;
772*9dfd9708SDario Binacchi 	unsigned int val;
773*9dfd9708SDario Binacchi 	int i, error;
77443c4d13eSSimon Budig 	size_t read = 0;
77543c4d13eSSimon Budig 	int colbytes;
77643c4d13eSSimon Budig 	u8 *rdbuf;
77743c4d13eSSimon Budig 
77843c4d13eSSimon Budig 	if (*off < 0 || *off >= tsdata->raw_bufsize)
77943c4d13eSSimon Budig 		return 0;
78043c4d13eSSimon Budig 
78143c4d13eSSimon Budig 	mutex_lock(&tsdata->mutex);
78243c4d13eSSimon Budig 
78343c4d13eSSimon Budig 	if (!tsdata->factory_mode || !tsdata->raw_buffer) {
78443c4d13eSSimon Budig 		error = -EIO;
78543c4d13eSSimon Budig 		goto out;
78643c4d13eSSimon Budig 	}
78743c4d13eSSimon Budig 
788*9dfd9708SDario Binacchi 	error = regmap_write(tsdata->regmap, 0x08, 0x01);
78943c4d13eSSimon Budig 	if (error) {
79024642661SDario Binacchi 		dev_err(&client->dev,
79143c4d13eSSimon Budig 			"failed to write 0x08 register, error %d\n", error);
79243c4d13eSSimon Budig 		goto out;
79343c4d13eSSimon Budig 	}
79443c4d13eSSimon Budig 
79543c4d13eSSimon Budig 	do {
7960eeecf60SAniroop Mathur 		usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100);
797*9dfd9708SDario Binacchi 		error = regmap_read(tsdata->regmap, 0x08, &val);
798*9dfd9708SDario Binacchi 		if (error) {
79924642661SDario Binacchi 			dev_err(&client->dev,
800*9dfd9708SDario Binacchi 				"failed to read 0x08 register, error %d\n",
801*9dfd9708SDario Binacchi 				error);
80243c4d13eSSimon Budig 			goto out;
80343c4d13eSSimon Budig 		}
80443c4d13eSSimon Budig 
805*9dfd9708SDario Binacchi 		if (val == 1)
806*9dfd9708SDario Binacchi 			break;
807*9dfd9708SDario Binacchi 	} while (--retries > 0);
808*9dfd9708SDario Binacchi 
80943c4d13eSSimon Budig 	if (retries == 0) {
81024642661SDario Binacchi 		dev_err(&client->dev,
81143c4d13eSSimon Budig 			"timed out waiting for register to settle\n");
81243c4d13eSSimon Budig 		error = -ETIMEDOUT;
81343c4d13eSSimon Budig 		goto out;
81443c4d13eSSimon Budig 	}
81543c4d13eSSimon Budig 
81643c4d13eSSimon Budig 	rdbuf = tsdata->raw_buffer;
81743c4d13eSSimon Budig 	colbytes = tsdata->num_y * sizeof(u16);
81843c4d13eSSimon Budig 
81943c4d13eSSimon Budig 	for (i = 0; i < tsdata->num_x; i++) {
820*9dfd9708SDario Binacchi 		rdbuf[0] = i;  /* column index */
821*9dfd9708SDario Binacchi 		error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes);
82243c4d13eSSimon Budig 		if (error)
82343c4d13eSSimon Budig 			goto out;
82443c4d13eSSimon Budig 
82543c4d13eSSimon Budig 		rdbuf += colbytes;
82643c4d13eSSimon Budig 	}
82743c4d13eSSimon Budig 
82843c4d13eSSimon Budig 	read = min_t(size_t, count, tsdata->raw_bufsize - *off);
82935b1da4eSAxel Lin 	if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) {
83035b1da4eSAxel Lin 		error = -EFAULT;
83135b1da4eSAxel Lin 		goto out;
83235b1da4eSAxel Lin 	}
83335b1da4eSAxel Lin 
83443c4d13eSSimon Budig 	*off += read;
83543c4d13eSSimon Budig out:
83643c4d13eSSimon Budig 	mutex_unlock(&tsdata->mutex);
83743c4d13eSSimon Budig 	return error ?: read;
83843c4d13eSSimon Budig };
83943c4d13eSSimon Budig 
84043c4d13eSSimon Budig static const struct file_operations debugfs_raw_data_fops = {
841f6c0df6aSWei Yongjun 	.open = simple_open,
84243c4d13eSSimon Budig 	.read = edt_ft5x06_debugfs_raw_data_read,
84343c4d13eSSimon Budig };
84443c4d13eSSimon Budig 
84521d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
84643c4d13eSSimon Budig 					  const char *debugfs_name)
84743c4d13eSSimon Budig {
84843c4d13eSSimon Budig 	tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
84943c4d13eSSimon Budig 
85043c4d13eSSimon Budig 	debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
85143c4d13eSSimon Budig 	debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
85243c4d13eSSimon Budig 
85343c4d13eSSimon Budig 	debugfs_create_file("mode", S_IRUSR | S_IWUSR,
85443c4d13eSSimon Budig 			    tsdata->debug_dir, tsdata, &debugfs_mode_fops);
85543c4d13eSSimon Budig 	debugfs_create_file("raw_data", S_IRUSR,
85643c4d13eSSimon Budig 			    tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
85743c4d13eSSimon Budig }
85843c4d13eSSimon Budig 
85921d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
86043c4d13eSSimon Budig {
86143c4d13eSSimon Budig 	debugfs_remove_recursive(tsdata->debug_dir);
862a1d0fa77SGuenter Roeck 	kfree(tsdata->raw_buffer);
86343c4d13eSSimon Budig }
86443c4d13eSSimon Budig 
86543c4d13eSSimon Budig #else
86643c4d13eSSimon Budig 
86721d1611aSMarco Felsch static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
86821d1611aSMarco Felsch {
86921d1611aSMarco Felsch 	return -ENOSYS;
87021d1611aSMarco Felsch }
87121d1611aSMarco Felsch 
87221d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
87343c4d13eSSimon Budig 					  const char *debugfs_name)
87443c4d13eSSimon Budig {
87543c4d13eSSimon Budig }
87643c4d13eSSimon Budig 
87721d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
87843c4d13eSSimon Budig {
87943c4d13eSSimon Budig }
88043c4d13eSSimon Budig 
88143c4d13eSSimon Budig #endif /* CONFIG_DEBUGFS */
88243c4d13eSSimon Budig 
8835298cc4cSBill Pemberton static int edt_ft5x06_ts_identify(struct i2c_client *client,
884480343dcSDario Binacchi 				  struct edt_ft5x06_ts_data *tsdata)
88543c4d13eSSimon Budig {
88643c4d13eSSimon Budig 	u8 rdbuf[EDT_NAME_LEN];
88743c4d13eSSimon Budig 	char *p;
88843c4d13eSSimon Budig 	int error;
889fd335ab0SLothar Waßmann 	char *model_name = tsdata->name;
890480343dcSDario Binacchi 	char *fw_version = tsdata->fw_version;
89143c4d13eSSimon Budig 
892fd335ab0SLothar Waßmann 	/* see what we find if we assume it is a M06 *
893fd335ab0SLothar Waßmann 	 * if we get less than EDT_NAME_LEN, we don't want
894fd335ab0SLothar Waßmann 	 * to have garbage in there
895fd335ab0SLothar Waßmann 	 */
896fd335ab0SLothar Waßmann 	memset(rdbuf, 0, sizeof(rdbuf));
897*9dfd9708SDario Binacchi 	error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1);
89843c4d13eSSimon Budig 	if (error)
89943c4d13eSSimon Budig 		return error;
90043c4d13eSSimon Budig 
901aed5d0eeSSimon Budig 	/* Probe content for something consistent.
902aed5d0eeSSimon Budig 	 * M06 starts with a response byte, M12 gives the data directly.
903aed5d0eeSSimon Budig 	 * M09/Generic does not provide model number information.
904fd335ab0SLothar Waßmann 	 */
905aed5d0eeSSimon Budig 	if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
906169110c3SSimon Budig 		tsdata->version = EDT_M06;
907fd335ab0SLothar Waßmann 
90843c4d13eSSimon Budig 		/* remove last '$' end marker */
90943c4d13eSSimon Budig 		rdbuf[EDT_NAME_LEN - 1] = '\0';
91043c4d13eSSimon Budig 		if (rdbuf[EDT_NAME_LEN - 2] == '$')
91143c4d13eSSimon Budig 			rdbuf[EDT_NAME_LEN - 2] = '\0';
91243c4d13eSSimon Budig 
91343c4d13eSSimon Budig 		/* look for Model/Version separator */
91443c4d13eSSimon Budig 		p = strchr(rdbuf, '*');
91543c4d13eSSimon Budig 		if (p)
91643c4d13eSSimon Budig 			*p++ = '\0';
917a9f08ad7SWolfram Sang 		strscpy(model_name, rdbuf + 1, EDT_NAME_LEN);
918a9f08ad7SWolfram Sang 		strscpy(fw_version, p ? p : "", EDT_NAME_LEN);
919*9dfd9708SDario Binacchi 
920*9dfd9708SDario Binacchi 		regmap_exit(tsdata->regmap);
921*9dfd9708SDario Binacchi 		tsdata->regmap = regmap_init_i2c(client,
922*9dfd9708SDario Binacchi 						 &edt_M06_i2c_regmap_config);
923*9dfd9708SDario Binacchi 		if (IS_ERR(tsdata->regmap)) {
924*9dfd9708SDario Binacchi 			dev_err(&client->dev, "regmap allocation failed\n");
925*9dfd9708SDario Binacchi 			return PTR_ERR(tsdata->regmap);
926*9dfd9708SDario Binacchi 		}
927aed5d0eeSSimon Budig 	} else if (!strncasecmp(rdbuf, "EP0", 3)) {
928aed5d0eeSSimon Budig 		tsdata->version = EDT_M12;
929aed5d0eeSSimon Budig 
930aed5d0eeSSimon Budig 		/* remove last '$' end marker */
931aed5d0eeSSimon Budig 		rdbuf[EDT_NAME_LEN - 2] = '\0';
932aed5d0eeSSimon Budig 		if (rdbuf[EDT_NAME_LEN - 3] == '$')
933aed5d0eeSSimon Budig 			rdbuf[EDT_NAME_LEN - 3] = '\0';
934aed5d0eeSSimon Budig 
935aed5d0eeSSimon Budig 		/* look for Model/Version separator */
936aed5d0eeSSimon Budig 		p = strchr(rdbuf, '*');
937aed5d0eeSSimon Budig 		if (p)
938aed5d0eeSSimon Budig 			*p++ = '\0';
939a9f08ad7SWolfram Sang 		strscpy(model_name, rdbuf, EDT_NAME_LEN);
940a9f08ad7SWolfram Sang 		strscpy(fw_version, p ? p : "", EDT_NAME_LEN);
941fd335ab0SLothar Waßmann 	} else {
942aed5d0eeSSimon Budig 		/* If it is not an EDT M06/M12 touchscreen, then the model
943169110c3SSimon Budig 		 * detection is a bit hairy. The different ft5x06
94462c5e854SDario Binacchi 		 * firmwares around don't reliably implement the
945169110c3SSimon Budig 		 * identification registers. Well, we'll take a shot.
946169110c3SSimon Budig 		 *
947169110c3SSimon Budig 		 * The main difference between generic focaltec based
948169110c3SSimon Budig 		 * touches and EDT M09 is that we know how to retrieve
949169110c3SSimon Budig 		 * the max coordinates for the latter.
950169110c3SSimon Budig 		 */
951169110c3SSimon Budig 		tsdata->version = GENERIC_FT;
952fd335ab0SLothar Waßmann 
953*9dfd9708SDario Binacchi 		error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2);
954fd335ab0SLothar Waßmann 		if (error)
955fd335ab0SLothar Waßmann 			return error;
956fd335ab0SLothar Waßmann 
957a9f08ad7SWolfram Sang 		strscpy(fw_version, rdbuf, 2);
958fd335ab0SLothar Waßmann 
959*9dfd9708SDario Binacchi 		error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1);
960fd335ab0SLothar Waßmann 		if (error)
961fd335ab0SLothar Waßmann 			return error;
962fd335ab0SLothar Waßmann 
963169110c3SSimon Budig 		/* This "model identification" is not exact. Unfortunately
964169110c3SSimon Budig 		 * not all firmwares for the ft5x06 put useful values in
965169110c3SSimon Budig 		 * the identification registers.
966169110c3SSimon Budig 		 */
967169110c3SSimon Budig 		switch (rdbuf[0]) {
968146ea9b6SOliver Graute 		case 0x11:   /* EDT EP0110M09 */
969169110c3SSimon Budig 		case 0x35:   /* EDT EP0350M09 */
970169110c3SSimon Budig 		case 0x43:   /* EDT EP0430M09 */
971169110c3SSimon Budig 		case 0x50:   /* EDT EP0500M09 */
972169110c3SSimon Budig 		case 0x57:   /* EDT EP0570M09 */
973169110c3SSimon Budig 		case 0x70:   /* EDT EP0700M09 */
974169110c3SSimon Budig 			tsdata->version = EDT_M09;
975fd335ab0SLothar Waßmann 			snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
976fd335ab0SLothar Waßmann 				 rdbuf[0] >> 4, rdbuf[0] & 0x0F);
977169110c3SSimon Budig 			break;
978169110c3SSimon Budig 		case 0xa1:   /* EDT EP1010ML00 */
979169110c3SSimon Budig 			tsdata->version = EDT_M09;
980169110c3SSimon Budig 			snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
981169110c3SSimon Budig 				 rdbuf[0] >> 4, rdbuf[0] & 0x0F);
982169110c3SSimon Budig 			break;
983169110c3SSimon Budig 		case 0x5a:   /* Solomon Goldentek Display */
984169110c3SSimon Budig 			snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
985169110c3SSimon Budig 			break;
986a2f39dacSMarco Felsch 		case 0x59:  /* Evervision Display with FT5xx6 TS */
987a2f39dacSMarco Felsch 			tsdata->version = EV_FT;
988*9dfd9708SDario Binacchi 			error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1);
989a2f39dacSMarco Felsch 			if (error)
990a2f39dacSMarco Felsch 				return error;
991a9f08ad7SWolfram Sang 			strscpy(fw_version, rdbuf, 1);
992a2f39dacSMarco Felsch 			snprintf(model_name, EDT_NAME_LEN,
993a2f39dacSMarco Felsch 				 "EVERVISION-FT5726NEi");
994a2f39dacSMarco Felsch 			break;
995169110c3SSimon Budig 		default:
996169110c3SSimon Budig 			snprintf(model_name, EDT_NAME_LEN,
997169110c3SSimon Budig 				 "generic ft5x06 (%02x)",
998169110c3SSimon Budig 				 rdbuf[0]);
999169110c3SSimon Budig 			break;
1000169110c3SSimon Budig 		}
1001fd335ab0SLothar Waßmann 	}
100243c4d13eSSimon Budig 
100343c4d13eSSimon Budig 	return 0;
100443c4d13eSSimon Budig }
100543c4d13eSSimon Budig 
10062e23b7a9SDmitry Torokhov static void edt_ft5x06_ts_get_defaults(struct device *dev,
1007dac90dc2SLothar Waßmann 				       struct edt_ft5x06_ts_data *tsdata)
1008dac90dc2SLothar Waßmann {
1009fd335ab0SLothar Waßmann 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
1010*9dfd9708SDario Binacchi 	struct regmap *regmap = tsdata->regmap;
10112e23b7a9SDmitry Torokhov 	u32 val;
10122e23b7a9SDmitry Torokhov 	int error;
1013fd335ab0SLothar Waßmann 
10142e23b7a9SDmitry Torokhov 	error = device_property_read_u32(dev, "threshold", &val);
1015dc262dfaSPhilipp Zabel 	if (!error) {
1016*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_threshold, val);
1017dc262dfaSPhilipp Zabel 		tsdata->threshold = val;
1018dc262dfaSPhilipp Zabel 	}
10192e23b7a9SDmitry Torokhov 
10202e23b7a9SDmitry Torokhov 	error = device_property_read_u32(dev, "gain", &val);
1021dc262dfaSPhilipp Zabel 	if (!error) {
1022*9dfd9708SDario Binacchi 		regmap_write(regmap, reg_addr->reg_gain, val);
1023dc262dfaSPhilipp Zabel 		tsdata->gain = val;
1024dc262dfaSPhilipp Zabel 	}
10252e23b7a9SDmitry Torokhov 
10262e23b7a9SDmitry Torokhov 	error = device_property_read_u32(dev, "offset", &val);
1027dc262dfaSPhilipp Zabel 	if (!error) {
1028255cdaf7SMarco Felsch 		if (reg_addr->reg_offset != NO_REGISTER)
1029*9dfd9708SDario Binacchi 			regmap_write(regmap, reg_addr->reg_offset, val);
1030dc262dfaSPhilipp Zabel 		tsdata->offset = val;
1031dc262dfaSPhilipp Zabel 	}
1032b6eba860SMarco Felsch 
1033b6eba860SMarco Felsch 	error = device_property_read_u32(dev, "offset-x", &val);
1034b6eba860SMarco Felsch 	if (!error) {
1035255cdaf7SMarco Felsch 		if (reg_addr->reg_offset_x != NO_REGISTER)
1036*9dfd9708SDario Binacchi 			regmap_write(regmap, reg_addr->reg_offset_x, val);
1037b6eba860SMarco Felsch 		tsdata->offset_x = val;
1038b6eba860SMarco Felsch 	}
1039b6eba860SMarco Felsch 
1040b6eba860SMarco Felsch 	error = device_property_read_u32(dev, "offset-y", &val);
1041b6eba860SMarco Felsch 	if (!error) {
1042255cdaf7SMarco Felsch 		if (reg_addr->reg_offset_y != NO_REGISTER)
1043*9dfd9708SDario Binacchi 			regmap_write(regmap, reg_addr->reg_offset_y, val);
1044b6eba860SMarco Felsch 		tsdata->offset_y = val;
1045b6eba860SMarco Felsch 	}
1046dac90dc2SLothar Waßmann }
1047dac90dc2SLothar Waßmann 
104803161a95SDmitry Torokhov static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
104943c4d13eSSimon Budig {
1050fd335ab0SLothar Waßmann 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
1051*9dfd9708SDario Binacchi 	struct regmap *regmap = tsdata->regmap;
1052*9dfd9708SDario Binacchi 	unsigned int val;
1053fd335ab0SLothar Waßmann 
1054*9dfd9708SDario Binacchi 	regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold);
1055*9dfd9708SDario Binacchi 	regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain);
1056a2f39dacSMarco Felsch 	if (reg_addr->reg_offset != NO_REGISTER)
1057*9dfd9708SDario Binacchi 		regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset);
1058b6eba860SMarco Felsch 	if (reg_addr->reg_offset_x != NO_REGISTER)
1059*9dfd9708SDario Binacchi 		regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x);
1060b6eba860SMarco Felsch 	if (reg_addr->reg_offset_y != NO_REGISTER)
1061*9dfd9708SDario Binacchi 		regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y);
1062fd335ab0SLothar Waßmann 	if (reg_addr->reg_report_rate != NO_REGISTER)
1063*9dfd9708SDario Binacchi 		regmap_read(regmap, reg_addr->reg_report_rate,
1064*9dfd9708SDario Binacchi 			    &tsdata->report_rate);
106503161a95SDmitry Torokhov 	tsdata->num_x = EDT_DEFAULT_NUM_X;
1066*9dfd9708SDario Binacchi 	if (reg_addr->reg_num_x != NO_REGISTER) {
1067*9dfd9708SDario Binacchi 		if (!regmap_read(regmap, reg_addr->reg_num_x, &val))
1068*9dfd9708SDario Binacchi 			tsdata->num_x = val;
1069*9dfd9708SDario Binacchi 	}
107003161a95SDmitry Torokhov 	tsdata->num_y = EDT_DEFAULT_NUM_Y;
1071*9dfd9708SDario Binacchi 	if (reg_addr->reg_num_y != NO_REGISTER) {
1072*9dfd9708SDario Binacchi 		if (!regmap_read(regmap, reg_addr->reg_num_y, &val))
1073*9dfd9708SDario Binacchi 			tsdata->num_y = val;
1074*9dfd9708SDario Binacchi 	}
1075fd335ab0SLothar Waßmann }
1076fd335ab0SLothar Waßmann 
107703161a95SDmitry Torokhov static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
1078fd335ab0SLothar Waßmann {
1079fd335ab0SLothar Waßmann 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
1080fd335ab0SLothar Waßmann 
1081fd335ab0SLothar Waßmann 	switch (tsdata->version) {
1082169110c3SSimon Budig 	case EDT_M06:
1083fd335ab0SLothar Waßmann 		reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
1084fd335ab0SLothar Waßmann 		reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
1085fd335ab0SLothar Waßmann 		reg_addr->reg_gain = WORK_REGISTER_GAIN;
1086fd335ab0SLothar Waßmann 		reg_addr->reg_offset = WORK_REGISTER_OFFSET;
1087b6eba860SMarco Felsch 		reg_addr->reg_offset_x = NO_REGISTER;
1088b6eba860SMarco Felsch 		reg_addr->reg_offset_y = NO_REGISTER;
1089fd335ab0SLothar Waßmann 		reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
1090fd335ab0SLothar Waßmann 		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
1091fd335ab0SLothar Waßmann 		break;
1092fd335ab0SLothar Waßmann 
1093169110c3SSimon Budig 	case EDT_M09:
1094aed5d0eeSSimon Budig 	case EDT_M12:
1095fd335ab0SLothar Waßmann 		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
109623ea98f4SDario Binacchi 		reg_addr->reg_report_rate = tsdata->version == EDT_M12 ?
109723ea98f4SDario Binacchi 			M12_REGISTER_REPORT_RATE : NO_REGISTER;
1098fd335ab0SLothar Waßmann 		reg_addr->reg_gain = M09_REGISTER_GAIN;
1099fd335ab0SLothar Waßmann 		reg_addr->reg_offset = M09_REGISTER_OFFSET;
1100b6eba860SMarco Felsch 		reg_addr->reg_offset_x = NO_REGISTER;
1101b6eba860SMarco Felsch 		reg_addr->reg_offset_y = NO_REGISTER;
1102fd335ab0SLothar Waßmann 		reg_addr->reg_num_x = M09_REGISTER_NUM_X;
1103fd335ab0SLothar Waßmann 		reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
1104fd335ab0SLothar Waßmann 		break;
1105169110c3SSimon Budig 
1106a2f39dacSMarco Felsch 	case EV_FT:
1107a2f39dacSMarco Felsch 		reg_addr->reg_threshold = EV_REGISTER_THRESHOLD;
110803161a95SDmitry Torokhov 		reg_addr->reg_report_rate = NO_REGISTER;
1109a2f39dacSMarco Felsch 		reg_addr->reg_gain = EV_REGISTER_GAIN;
1110a2f39dacSMarco Felsch 		reg_addr->reg_offset = NO_REGISTER;
1111b6eba860SMarco Felsch 		reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X;
1112b6eba860SMarco Felsch 		reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y;
1113a2f39dacSMarco Felsch 		reg_addr->reg_num_x = NO_REGISTER;
1114a2f39dacSMarco Felsch 		reg_addr->reg_num_y = NO_REGISTER;
1115a2f39dacSMarco Felsch 		break;
1116a2f39dacSMarco Felsch 
1117169110c3SSimon Budig 	case GENERIC_FT:
1118169110c3SSimon Budig 		/* this is a guesswork */
1119169110c3SSimon Budig 		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
112003161a95SDmitry Torokhov 		reg_addr->reg_report_rate = NO_REGISTER;
1121169110c3SSimon Budig 		reg_addr->reg_gain = M09_REGISTER_GAIN;
1122169110c3SSimon Budig 		reg_addr->reg_offset = M09_REGISTER_OFFSET;
1123b6eba860SMarco Felsch 		reg_addr->reg_offset_x = NO_REGISTER;
1124b6eba860SMarco Felsch 		reg_addr->reg_offset_y = NO_REGISTER;
112503161a95SDmitry Torokhov 		reg_addr->reg_num_x = NO_REGISTER;
112603161a95SDmitry Torokhov 		reg_addr->reg_num_y = NO_REGISTER;
1127169110c3SSimon Budig 		break;
1128fd335ab0SLothar Waßmann 	}
112943c4d13eSSimon Budig }
113043c4d13eSSimon Budig 
1131df4c40f4SStephan Gerhold static void edt_ft5x06_disable_regulators(void *arg)
11327448bfecSMylène Josserand {
11337448bfecSMylène Josserand 	struct edt_ft5x06_ts_data *data = arg;
11347448bfecSMylène Josserand 
11357448bfecSMylène Josserand 	regulator_disable(data->vcc);
1136df4c40f4SStephan Gerhold 	regulator_disable(data->iovcc);
11377448bfecSMylène Josserand }
11387448bfecSMylène Josserand 
1139e7c31218SUwe Kleine-König static int edt_ft5x06_ts_probe(struct i2c_client *client)
114043c4d13eSSimon Budig {
1141e7c31218SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
1142b1d2a3ecSFranklin S Cooper Jr 	const struct edt_i2c_chip_data *chip_data;
114343c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata;
1144*9dfd9708SDario Binacchi 	unsigned int val;
114543c4d13eSSimon Budig 	struct input_dev *input;
1146f0bef75cSDmitry Torokhov 	unsigned long irq_flags;
114743c4d13eSSimon Budig 	int error;
11485bcee83aSDario Binacchi 	u32 report_rate;
114943c4d13eSSimon Budig 
115043c4d13eSSimon Budig 	dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
115143c4d13eSSimon Budig 
115202300bd6SLothar Waßmann 	tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
115302300bd6SLothar Waßmann 	if (!tsdata) {
115443c4d13eSSimon Budig 		dev_err(&client->dev, "failed to allocate driver data.\n");
115502300bd6SLothar Waßmann 		return -ENOMEM;
115602300bd6SLothar Waßmann 	}
115702300bd6SLothar Waßmann 
1158*9dfd9708SDario Binacchi 	tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config);
1159*9dfd9708SDario Binacchi 	if (IS_ERR(tsdata->regmap)) {
1160*9dfd9708SDario Binacchi 		dev_err(&client->dev, "regmap allocation failed\n");
1161*9dfd9708SDario Binacchi 		return PTR_ERR(tsdata->regmap);
1162*9dfd9708SDario Binacchi 	}
1163*9dfd9708SDario Binacchi 
1164fc226eb2SAndy Shevchenko 	chip_data = device_get_match_data(&client->dev);
1165b1d2a3ecSFranklin S Cooper Jr 	if (!chip_data)
1166b1d2a3ecSFranklin S Cooper Jr 		chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
1167b1d2a3ecSFranklin S Cooper Jr 	if (!chip_data || !chip_data->max_support_points) {
1168b1d2a3ecSFranklin S Cooper Jr 		dev_err(&client->dev, "invalid or missing chip data\n");
1169b1d2a3ecSFranklin S Cooper Jr 		return -EINVAL;
1170b1d2a3ecSFranklin S Cooper Jr 	}
1171b1d2a3ecSFranklin S Cooper Jr 
1172b1d2a3ecSFranklin S Cooper Jr 	tsdata->max_support_points = chip_data->max_support_points;
1173b1d2a3ecSFranklin S Cooper Jr 
11747448bfecSMylène Josserand 	tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
11757448bfecSMylène Josserand 	if (IS_ERR(tsdata->vcc)) {
11767448bfecSMylène Josserand 		error = PTR_ERR(tsdata->vcc);
11777448bfecSMylène Josserand 		if (error != -EPROBE_DEFER)
11787448bfecSMylène Josserand 			dev_err(&client->dev,
11797448bfecSMylène Josserand 				"failed to request regulator: %d\n", error);
11807448bfecSMylène Josserand 		return error;
11817448bfecSMylène Josserand 	}
11827448bfecSMylène Josserand 
1183df4c40f4SStephan Gerhold 	tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
1184df4c40f4SStephan Gerhold 	if (IS_ERR(tsdata->iovcc)) {
1185df4c40f4SStephan Gerhold 		error = PTR_ERR(tsdata->iovcc);
1186df4c40f4SStephan Gerhold 		if (error != -EPROBE_DEFER)
1187df4c40f4SStephan Gerhold 			dev_err(&client->dev,
1188df4c40f4SStephan Gerhold 				"failed to request iovcc regulator: %d\n", error);
1189df4c40f4SStephan Gerhold 		return error;
1190df4c40f4SStephan Gerhold 	}
1191df4c40f4SStephan Gerhold 
1192df4c40f4SStephan Gerhold 	error = regulator_enable(tsdata->iovcc);
1193df4c40f4SStephan Gerhold 	if (error < 0) {
1194df4c40f4SStephan Gerhold 		dev_err(&client->dev, "failed to enable iovcc: %d\n", error);
1195df4c40f4SStephan Gerhold 		return error;
1196df4c40f4SStephan Gerhold 	}
1197df4c40f4SStephan Gerhold 
1198df4c40f4SStephan Gerhold 	/* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
1199df4c40f4SStephan Gerhold 	usleep_range(10, 100);
1200df4c40f4SStephan Gerhold 
12017448bfecSMylène Josserand 	error = regulator_enable(tsdata->vcc);
12027448bfecSMylène Josserand 	if (error < 0) {
12037448bfecSMylène Josserand 		dev_err(&client->dev, "failed to enable vcc: %d\n", error);
1204df4c40f4SStephan Gerhold 		regulator_disable(tsdata->iovcc);
12057448bfecSMylène Josserand 		return error;
12067448bfecSMylène Josserand 	}
12077448bfecSMylène Josserand 
12087448bfecSMylène Josserand 	error = devm_add_action_or_reset(&client->dev,
1209df4c40f4SStephan Gerhold 					 edt_ft5x06_disable_regulators,
12107448bfecSMylène Josserand 					 tsdata);
12117448bfecSMylène Josserand 	if (error)
12127448bfecSMylène Josserand 		return error;
12137448bfecSMylène Josserand 
121413c23cd1SFranklin S Cooper Jr 	tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
121513c23cd1SFranklin S Cooper Jr 						     "reset", GPIOD_OUT_HIGH);
121613c23cd1SFranklin S Cooper Jr 	if (IS_ERR(tsdata->reset_gpio)) {
121713c23cd1SFranklin S Cooper Jr 		error = PTR_ERR(tsdata->reset_gpio);
1218dac90dc2SLothar Waßmann 		dev_err(&client->dev,
121913c23cd1SFranklin S Cooper Jr 			"Failed to request GPIO reset pin, error %d\n", error);
1220dac90dc2SLothar Waßmann 		return error;
1221dac90dc2SLothar Waßmann 	}
1222dac90dc2SLothar Waßmann 
122313c23cd1SFranklin S Cooper Jr 	tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev,
122413c23cd1SFranklin S Cooper Jr 						    "wake", GPIOD_OUT_LOW);
122513c23cd1SFranklin S Cooper Jr 	if (IS_ERR(tsdata->wake_gpio)) {
122613c23cd1SFranklin S Cooper Jr 		error = PTR_ERR(tsdata->wake_gpio);
1227dac90dc2SLothar Waßmann 		dev_err(&client->dev,
122813c23cd1SFranklin S Cooper Jr 			"Failed to request GPIO wake pin, error %d\n", error);
1229dac90dc2SLothar Waßmann 		return error;
1230dac90dc2SLothar Waßmann 	}
123113c23cd1SFranklin S Cooper Jr 
123221d1611aSMarco Felsch 	/*
123321d1611aSMarco Felsch 	 * Check which sleep modes we can support. Power-off requieres the
123421d1611aSMarco Felsch 	 * reset-pin to ensure correct power-down/power-up behaviour. Start with
123521d1611aSMarco Felsch 	 * the EDT_PMODE_POWEROFF test since this is the deepest possible sleep
123621d1611aSMarco Felsch 	 * mode.
123721d1611aSMarco Felsch 	 */
123821d1611aSMarco Felsch 	if (tsdata->reset_gpio)
123921d1611aSMarco Felsch 		tsdata->suspend_mode = EDT_PMODE_POWEROFF;
124021d1611aSMarco Felsch 	else if (tsdata->wake_gpio)
124121d1611aSMarco Felsch 		tsdata->suspend_mode = EDT_PMODE_HIBERNATE;
124221d1611aSMarco Felsch 	else
124321d1611aSMarco Felsch 		tsdata->suspend_mode = EDT_PMODE_NOT_SUPPORTED;
124421d1611aSMarco Felsch 
124513c23cd1SFranklin S Cooper Jr 	if (tsdata->wake_gpio) {
124613c23cd1SFranklin S Cooper Jr 		usleep_range(5000, 6000);
124713c23cd1SFranklin S Cooper Jr 		gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
124813c23cd1SFranklin S Cooper Jr 	}
124913c23cd1SFranklin S Cooper Jr 
125013c23cd1SFranklin S Cooper Jr 	if (tsdata->reset_gpio) {
125113c23cd1SFranklin S Cooper Jr 		usleep_range(5000, 6000);
125213c23cd1SFranklin S Cooper Jr 		gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
125313c23cd1SFranklin S Cooper Jr 		msleep(300);
1254dac90dc2SLothar Waßmann 	}
1255dac90dc2SLothar Waßmann 
125602300bd6SLothar Waßmann 	input = devm_input_allocate_device(&client->dev);
125702300bd6SLothar Waßmann 	if (!input) {
125802300bd6SLothar Waßmann 		dev_err(&client->dev, "failed to allocate input device.\n");
125902300bd6SLothar Waßmann 		return -ENOMEM;
126043c4d13eSSimon Budig 	}
126143c4d13eSSimon Budig 
126243c4d13eSSimon Budig 	mutex_init(&tsdata->mutex);
126343c4d13eSSimon Budig 	tsdata->client = client;
126443c4d13eSSimon Budig 	tsdata->input = input;
126543c4d13eSSimon Budig 	tsdata->factory_mode = false;
1266*9dfd9708SDario Binacchi 	i2c_set_clientdata(client, tsdata);
126743c4d13eSSimon Budig 
1268480343dcSDario Binacchi 	error = edt_ft5x06_ts_identify(client, tsdata);
126943c4d13eSSimon Budig 	if (error) {
127043c4d13eSSimon Budig 		dev_err(&client->dev, "touchscreen probe failed\n");
127102300bd6SLothar Waßmann 		return error;
127243c4d13eSSimon Budig 	}
127343c4d13eSSimon Budig 
1274e112324cSPhilipp Zabel 	/*
1275e112324cSPhilipp Zabel 	 * Dummy read access. EP0700MLP1 returns bogus data on the first
1276e112324cSPhilipp Zabel 	 * register read access and ignores writes.
1277e112324cSPhilipp Zabel 	 */
1278*9dfd9708SDario Binacchi 	regmap_read(tsdata->regmap, 0x00, &val);
1279e112324cSPhilipp Zabel 
1280fd335ab0SLothar Waßmann 	edt_ft5x06_ts_set_regs(tsdata);
12812e23b7a9SDmitry Torokhov 	edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
128243c4d13eSSimon Budig 	edt_ft5x06_ts_get_parameters(tsdata);
128343c4d13eSSimon Budig 
12845bcee83aSDario Binacchi 	if (tsdata->reg_addr.reg_report_rate != NO_REGISTER &&
12855bcee83aSDario Binacchi 	    !device_property_read_u32(&client->dev,
12865bcee83aSDario Binacchi 				      "report-rate-hz", &report_rate)) {
12875bcee83aSDario Binacchi 		if (tsdata->version == EDT_M06)
12885bcee83aSDario Binacchi 			tsdata->report_rate = clamp_val(report_rate, 30, 140);
12895bcee83aSDario Binacchi 		else
12905bcee83aSDario Binacchi 			tsdata->report_rate = clamp_val(report_rate, 1, 255);
12915bcee83aSDario Binacchi 
12925bcee83aSDario Binacchi 		if (report_rate != tsdata->report_rate)
12935bcee83aSDario Binacchi 			dev_warn(&client->dev,
12945bcee83aSDario Binacchi 				 "report-rate %dHz is unsupported, use %dHz\n",
12955bcee83aSDario Binacchi 				 report_rate, tsdata->report_rate);
12965bcee83aSDario Binacchi 
12975bcee83aSDario Binacchi 		if (tsdata->version == EDT_M06)
12985bcee83aSDario Binacchi 			tsdata->report_rate /= 10;
12995bcee83aSDario Binacchi 
1300*9dfd9708SDario Binacchi 		regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate,
13015bcee83aSDario Binacchi 			     tsdata->report_rate);
13025bcee83aSDario Binacchi 	}
13035bcee83aSDario Binacchi 
130443c4d13eSSimon Budig 	dev_dbg(&client->dev,
130543c4d13eSSimon Budig 		"Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
1306480343dcSDario Binacchi 		tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y);
130743c4d13eSSimon Budig 
130843c4d13eSSimon Budig 	input->name = tsdata->name;
130943c4d13eSSimon Budig 	input->id.bustype = BUS_I2C;
131043c4d13eSSimon Budig 	input->dev.parent = &client->dev;
131143c4d13eSSimon Budig 
131243c4d13eSSimon Budig 	input_set_abs_params(input, ABS_MT_POSITION_X,
131343c4d13eSSimon Budig 			     0, tsdata->num_x * 64 - 1, 0, 0);
131443c4d13eSSimon Budig 	input_set_abs_params(input, ABS_MT_POSITION_Y,
131543c4d13eSSimon Budig 			     0, tsdata->num_y * 64 - 1, 0, 0);
13162c005598SMaxime Ripard 
1317ad368eb2SHans de Goede 	touchscreen_parse_properties(input, true, &tsdata->prop);
13182c005598SMaxime Ripard 
1319b1d2a3ecSFranklin S Cooper Jr 	error = input_mt_init_slots(input, tsdata->max_support_points,
1320b1d2a3ecSFranklin S Cooper Jr 				    INPUT_MT_DIRECT);
132143c4d13eSSimon Budig 	if (error) {
132243c4d13eSSimon Budig 		dev_err(&client->dev, "Unable to init MT slots.\n");
132302300bd6SLothar Waßmann 		return error;
132443c4d13eSSimon Budig 	}
132543c4d13eSSimon Budig 
1326f0bef75cSDmitry Torokhov 	irq_flags = irq_get_trigger_type(client->irq);
1327f0bef75cSDmitry Torokhov 	if (irq_flags == IRQF_TRIGGER_NONE)
1328f0bef75cSDmitry Torokhov 		irq_flags = IRQF_TRIGGER_FALLING;
1329f0bef75cSDmitry Torokhov 	irq_flags |= IRQF_ONESHOT;
1330f0bef75cSDmitry Torokhov 
1331f0bef75cSDmitry Torokhov 	error = devm_request_threaded_irq(&client->dev, client->irq,
1332f0bef75cSDmitry Torokhov 					  NULL, edt_ft5x06_ts_isr, irq_flags,
133343c4d13eSSimon Budig 					  client->name, tsdata);
133443c4d13eSSimon Budig 	if (error) {
133543c4d13eSSimon Budig 		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
133602300bd6SLothar Waßmann 		return error;
133743c4d13eSSimon Budig 	}
133843c4d13eSSimon Budig 
1339e3adf559SAndi Shyti 	error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
134043c4d13eSSimon Budig 	if (error)
134102300bd6SLothar Waßmann 		return error;
134243c4d13eSSimon Budig 
134343c4d13eSSimon Budig 	error = input_register_device(input);
1344dac90dc2SLothar Waßmann 	if (error)
1345e3adf559SAndi Shyti 		return error;
134643c4d13eSSimon Budig 
134743c4d13eSSimon Budig 	edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
134843c4d13eSSimon Budig 
134943c4d13eSSimon Budig 	dev_dbg(&client->dev,
1350dac90dc2SLothar Waßmann 		"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
13518b58cc36SFranklin S Cooper Jr 		client->irq,
13528b58cc36SFranklin S Cooper Jr 		tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1,
13538b58cc36SFranklin S Cooper Jr 		tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
135443c4d13eSSimon Budig 
135543c4d13eSSimon Budig 	return 0;
135643c4d13eSSimon Budig }
135743c4d13eSSimon Budig 
1358ed5c2f5fSUwe Kleine-König static void edt_ft5x06_ts_remove(struct i2c_client *client)
135943c4d13eSSimon Budig {
136043c4d13eSSimon Budig 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
136143c4d13eSSimon Budig 
136243c4d13eSSimon Budig 	edt_ft5x06_ts_teardown_debugfs(tsdata);
1363*9dfd9708SDario Binacchi 	regmap_exit(tsdata->regmap);
136443c4d13eSSimon Budig }
136543c4d13eSSimon Budig 
13666e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_suspend(struct device *dev)
136721d1611aSMarco Felsch {
136821d1611aSMarco Felsch 	struct i2c_client *client = to_i2c_client(dev);
136921d1611aSMarco Felsch 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
137021d1611aSMarco Felsch 	struct gpio_desc *reset_gpio = tsdata->reset_gpio;
137121d1611aSMarco Felsch 	int ret;
137221d1611aSMarco Felsch 
137321d1611aSMarco Felsch 	if (device_may_wakeup(dev))
137421d1611aSMarco Felsch 		return 0;
137521d1611aSMarco Felsch 
137621d1611aSMarco Felsch 	if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED)
137721d1611aSMarco Felsch 		return 0;
137821d1611aSMarco Felsch 
137921d1611aSMarco Felsch 	/* Enter hibernate mode. */
1380*9dfd9708SDario Binacchi 	ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE,
138121d1611aSMarco Felsch 			   PMOD_REGISTER_HIBERNATE);
138221d1611aSMarco Felsch 	if (ret)
138321d1611aSMarco Felsch 		dev_warn(dev, "Failed to set hibernate mode\n");
138421d1611aSMarco Felsch 
138521d1611aSMarco Felsch 	if (tsdata->suspend_mode == EDT_PMODE_HIBERNATE)
138621d1611aSMarco Felsch 		return 0;
138721d1611aSMarco Felsch 
138821d1611aSMarco Felsch 	/*
138921d1611aSMarco Felsch 	 * Power-off according the datasheet. Cut the power may leaf the irq
139021d1611aSMarco Felsch 	 * line in an undefined state depending on the host pull resistor
139121d1611aSMarco Felsch 	 * settings. Disable the irq to avoid adjusting each host till the
139221d1611aSMarco Felsch 	 * device is back in a full functional state.
139321d1611aSMarco Felsch 	 */
139421d1611aSMarco Felsch 	disable_irq(tsdata->client->irq);
139521d1611aSMarco Felsch 
139621d1611aSMarco Felsch 	gpiod_set_value_cansleep(reset_gpio, 1);
139721d1611aSMarco Felsch 	usleep_range(1000, 2000);
139821d1611aSMarco Felsch 
139921d1611aSMarco Felsch 	ret = regulator_disable(tsdata->vcc);
140021d1611aSMarco Felsch 	if (ret)
140121d1611aSMarco Felsch 		dev_warn(dev, "Failed to disable vcc\n");
1402df4c40f4SStephan Gerhold 	ret = regulator_disable(tsdata->iovcc);
1403df4c40f4SStephan Gerhold 	if (ret)
1404df4c40f4SStephan Gerhold 		dev_warn(dev, "Failed to disable iovcc\n");
140521d1611aSMarco Felsch 
140621d1611aSMarco Felsch 	return 0;
140721d1611aSMarco Felsch }
140821d1611aSMarco Felsch 
14096e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_resume(struct device *dev)
141021d1611aSMarco Felsch {
141121d1611aSMarco Felsch 	struct i2c_client *client = to_i2c_client(dev);
141221d1611aSMarco Felsch 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
141321d1611aSMarco Felsch 	int ret = 0;
141421d1611aSMarco Felsch 
141521d1611aSMarco Felsch 	if (device_may_wakeup(dev))
141621d1611aSMarco Felsch 		return 0;
141721d1611aSMarco Felsch 
141821d1611aSMarco Felsch 	if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED)
141921d1611aSMarco Felsch 		return 0;
142021d1611aSMarco Felsch 
142121d1611aSMarco Felsch 	if (tsdata->suspend_mode == EDT_PMODE_POWEROFF) {
142221d1611aSMarco Felsch 		struct gpio_desc *reset_gpio = tsdata->reset_gpio;
142321d1611aSMarco Felsch 
142421d1611aSMarco Felsch 		/*
142521d1611aSMarco Felsch 		 * We can't check if the regulator is a dummy or a real
142621d1611aSMarco Felsch 		 * regulator. So we need to specify the 5ms reset time (T_rst)
142721d1611aSMarco Felsch 		 * here instead of the 100us T_rtp time. We also need to wait
142821d1611aSMarco Felsch 		 * 300ms in case it was a real supply and the power was cutted
142921d1611aSMarco Felsch 		 * of. Toggle the reset pin is also a way to exit the hibernate
143021d1611aSMarco Felsch 		 * mode.
143121d1611aSMarco Felsch 		 */
143221d1611aSMarco Felsch 		gpiod_set_value_cansleep(reset_gpio, 1);
143321d1611aSMarco Felsch 		usleep_range(5000, 6000);
143421d1611aSMarco Felsch 
1435df4c40f4SStephan Gerhold 		ret = regulator_enable(tsdata->iovcc);
1436df4c40f4SStephan Gerhold 		if (ret) {
1437df4c40f4SStephan Gerhold 			dev_err(dev, "Failed to enable iovcc\n");
1438df4c40f4SStephan Gerhold 			return ret;
1439df4c40f4SStephan Gerhold 		}
1440df4c40f4SStephan Gerhold 
1441df4c40f4SStephan Gerhold 		/* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
1442df4c40f4SStephan Gerhold 		usleep_range(10, 100);
1443df4c40f4SStephan Gerhold 
144421d1611aSMarco Felsch 		ret = regulator_enable(tsdata->vcc);
144521d1611aSMarco Felsch 		if (ret) {
144621d1611aSMarco Felsch 			dev_err(dev, "Failed to enable vcc\n");
1447df4c40f4SStephan Gerhold 			regulator_disable(tsdata->iovcc);
144821d1611aSMarco Felsch 			return ret;
144921d1611aSMarco Felsch 		}
145021d1611aSMarco Felsch 
145121d1611aSMarco Felsch 		usleep_range(1000, 2000);
145221d1611aSMarco Felsch 		gpiod_set_value_cansleep(reset_gpio, 0);
145321d1611aSMarco Felsch 		msleep(300);
145421d1611aSMarco Felsch 
145521d1611aSMarco Felsch 		edt_ft5x06_restore_reg_parameters(tsdata);
145621d1611aSMarco Felsch 		enable_irq(tsdata->client->irq);
145721d1611aSMarco Felsch 
145821d1611aSMarco Felsch 		if (tsdata->factory_mode)
145921d1611aSMarco Felsch 			ret = edt_ft5x06_factory_mode(tsdata);
146021d1611aSMarco Felsch 	} else {
146121d1611aSMarco Felsch 		struct gpio_desc *wake_gpio = tsdata->wake_gpio;
146221d1611aSMarco Felsch 
146321d1611aSMarco Felsch 		gpiod_set_value_cansleep(wake_gpio, 0);
146421d1611aSMarco Felsch 		usleep_range(5000, 6000);
146521d1611aSMarco Felsch 		gpiod_set_value_cansleep(wake_gpio, 1);
146621d1611aSMarco Felsch 	}
146721d1611aSMarco Felsch 
146821d1611aSMarco Felsch 	return ret;
146921d1611aSMarco Felsch }
147021d1611aSMarco Felsch 
14716e6ebfc5SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
147221d1611aSMarco Felsch 				edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
147321d1611aSMarco Felsch 
1474b1d2a3ecSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5x06_data = {
1475b1d2a3ecSFranklin S Cooper Jr 	.max_support_points = 5,
1476b1d2a3ecSFranklin S Cooper Jr };
1477b1d2a3ecSFranklin S Cooper Jr 
1478af33e0adSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5506_data = {
1479af33e0adSFranklin S Cooper Jr 	.max_support_points = 10,
1480af33e0adSFranklin S Cooper Jr };
1481af33e0adSFranklin S Cooper Jr 
1482d1871654SHans de Goede static const struct edt_i2c_chip_data edt_ft6236_data = {
1483d1871654SHans de Goede 	.max_support_points = 2,
1484d1871654SHans de Goede };
1485d1871654SHans de Goede 
148643c4d13eSSimon Budig static const struct i2c_device_id edt_ft5x06_ts_id[] = {
1487b1d2a3ecSFranklin S Cooper Jr 	{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
1488af33e0adSFranklin S Cooper Jr 	{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
1489a2f39dacSMarco Felsch 	{ .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data },
1490d1871654SHans de Goede 	/* Note no edt- prefix for compatibility with the ft6236.c driver */
1491d1871654SHans de Goede 	{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
14921730d814SLothar Waßmann 	{ /* sentinel */ }
149343c4d13eSSimon Budig };
149443c4d13eSSimon Budig MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
149543c4d13eSSimon Budig 
1496dac90dc2SLothar Waßmann static const struct of_device_id edt_ft5x06_of_match[] = {
1497b1d2a3ecSFranklin S Cooper Jr 	{ .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
1498b1d2a3ecSFranklin S Cooper Jr 	{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
1499b1d2a3ecSFranklin S Cooper Jr 	{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
1500af33e0adSFranklin S Cooper Jr 	{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
1501a2f39dacSMarco Felsch 	{ .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data },
1502d1871654SHans de Goede 	/* Note focaltech vendor prefix for compatibility with ft6236.c */
1503d1871654SHans de Goede 	{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
1504dac90dc2SLothar Waßmann 	{ /* sentinel */ }
1505dac90dc2SLothar Waßmann };
1506dac90dc2SLothar Waßmann MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
1507dac90dc2SLothar Waßmann 
150843c4d13eSSimon Budig static struct i2c_driver edt_ft5x06_ts_driver = {
150943c4d13eSSimon Budig 	.driver = {
151043c4d13eSSimon Budig 		.name = "edt_ft5x06",
1511fc226eb2SAndy Shevchenko 		.of_match_table = edt_ft5x06_of_match,
15126e6ebfc5SJonathan Cameron 		.pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops),
15130f58daaaSAhmad Fatoum 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
151443c4d13eSSimon Budig 	},
151543c4d13eSSimon Budig 	.id_table = edt_ft5x06_ts_id,
1516e7c31218SUwe Kleine-König 	.probe_new = edt_ft5x06_ts_probe,
15171cb0aa88SBill Pemberton 	.remove   = edt_ft5x06_ts_remove,
151843c4d13eSSimon Budig };
151943c4d13eSSimon Budig 
152043c4d13eSSimon Budig module_i2c_driver(edt_ft5x06_ts_driver);
152143c4d13eSSimon Budig 
152243c4d13eSSimon Budig MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
152343c4d13eSSimon Budig MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
15246d3a41abSAndy Shevchenko MODULE_LICENSE("GPL v2");
1525