xref: /openbmc/linux/drivers/input/touchscreen/cyttsp4_core.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
217fb1563SFerruh Yigit /*
317fb1563SFerruh Yigit  * cyttsp4_core.c
417fb1563SFerruh Yigit  * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
517fb1563SFerruh Yigit  * For use with Cypress Txx4xx parts.
617fb1563SFerruh Yigit  * Supported parts include:
717fb1563SFerruh Yigit  * TMA4XX
817fb1563SFerruh Yigit  * TMA1036
917fb1563SFerruh Yigit  *
1017fb1563SFerruh Yigit  * Copyright (C) 2012 Cypress Semiconductor
1117fb1563SFerruh Yigit  *
1217fb1563SFerruh Yigit  * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
1317fb1563SFerruh Yigit  */
1417fb1563SFerruh Yigit 
1517fb1563SFerruh Yigit #include "cyttsp4_core.h"
1617fb1563SFerruh Yigit #include <linux/delay.h>
1717fb1563SFerruh Yigit #include <linux/gpio.h>
1817fb1563SFerruh Yigit #include <linux/input/mt.h>
1917fb1563SFerruh Yigit #include <linux/interrupt.h>
2017fb1563SFerruh Yigit #include <linux/pm_runtime.h>
2117fb1563SFerruh Yigit #include <linux/sched.h>
2217fb1563SFerruh Yigit #include <linux/slab.h>
2317fb1563SFerruh Yigit 
2417fb1563SFerruh Yigit /* Timeout in ms. */
2517fb1563SFerruh Yigit #define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT	500
2617fb1563SFerruh Yigit #define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT	5000
2717fb1563SFerruh Yigit #define CY_CORE_MODE_CHANGE_TIMEOUT		1000
2817fb1563SFerruh Yigit #define CY_CORE_RESET_AND_WAIT_TIMEOUT		500
2917fb1563SFerruh Yigit #define CY_CORE_WAKEUP_TIMEOUT			500
3017fb1563SFerruh Yigit 
3117fb1563SFerruh Yigit #define CY_CORE_STARTUP_RETRY_COUNT		3
3217fb1563SFerruh Yigit 
3345353186SLee Jones static const char * const cyttsp4_tch_abs_string[] = {
3445353186SLee Jones 	[CY_TCH_X]	= "X",
3545353186SLee Jones 	[CY_TCH_Y]	= "Y",
3645353186SLee Jones 	[CY_TCH_P]	= "P",
3745353186SLee Jones 	[CY_TCH_T]	= "T",
3845353186SLee Jones 	[CY_TCH_E]	= "E",
3945353186SLee Jones 	[CY_TCH_O]	= "O",
4045353186SLee Jones 	[CY_TCH_W]	= "W",
4145353186SLee Jones 	[CY_TCH_MAJ]	= "MAJ",
4245353186SLee Jones 	[CY_TCH_MIN]	= "MIN",
4345353186SLee Jones 	[CY_TCH_OR]	= "OR",
4445353186SLee Jones 	[CY_TCH_NUM_ABS] = "INVALID"
4545353186SLee Jones };
4645353186SLee Jones 
4717fb1563SFerruh Yigit static const u8 ldr_exit[] = {
4817fb1563SFerruh Yigit 	0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
4917fb1563SFerruh Yigit };
5017fb1563SFerruh Yigit 
5117fb1563SFerruh Yigit static const u8 ldr_err_app[] = {
5217fb1563SFerruh Yigit 	0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17
5317fb1563SFerruh Yigit };
5417fb1563SFerruh Yigit 
merge_bytes(u8 high,u8 low)5517fb1563SFerruh Yigit static inline size_t merge_bytes(u8 high, u8 low)
5617fb1563SFerruh Yigit {
5717fb1563SFerruh Yigit 	return (high << 8) + low;
5817fb1563SFerruh Yigit }
5917fb1563SFerruh Yigit 
6017fb1563SFerruh Yigit #ifdef VERBOSE_DEBUG
cyttsp4_pr_buf(struct device * dev,u8 * pr_buf,u8 * dptr,int size,const char * data_name)6117fb1563SFerruh Yigit static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
6217fb1563SFerruh Yigit 		const char *data_name)
6317fb1563SFerruh Yigit {
6417fb1563SFerruh Yigit 	int i, k;
6517fb1563SFerruh Yigit 	const char fmt[] = "%02X ";
6617fb1563SFerruh Yigit 	int max;
6717fb1563SFerruh Yigit 
6817fb1563SFerruh Yigit 	if (!size)
6917fb1563SFerruh Yigit 		return;
7017fb1563SFerruh Yigit 
7117fb1563SFerruh Yigit 	max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
7217fb1563SFerruh Yigit 
7317fb1563SFerruh Yigit 	pr_buf[0] = 0;
7417fb1563SFerruh Yigit 	for (i = k = 0; i < size && k < max; i++, k += 3)
7517fb1563SFerruh Yigit 		scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
7617fb1563SFerruh Yigit 
7717fb1563SFerruh Yigit 	dev_vdbg(dev, "%s:  %s[0..%d]=%s%s\n", __func__, data_name, size - 1,
7817fb1563SFerruh Yigit 			pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
7917fb1563SFerruh Yigit }
8017fb1563SFerruh Yigit #else
8117fb1563SFerruh Yigit #define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0)
8217fb1563SFerruh Yigit #endif
8317fb1563SFerruh Yigit 
cyttsp4_load_status_regs(struct cyttsp4 * cd)8417fb1563SFerruh Yigit static int cyttsp4_load_status_regs(struct cyttsp4 *cd)
8517fb1563SFerruh Yigit {
8617fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
8717fb1563SFerruh Yigit 	struct device *dev = cd->dev;
8817fb1563SFerruh Yigit 	int rc;
8917fb1563SFerruh Yigit 
9017fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size,
9117fb1563SFerruh Yigit 			si->xy_mode);
9217fb1563SFerruh Yigit 	if (rc < 0)
9317fb1563SFerruh Yigit 		dev_err(dev, "%s: fail read mode regs r=%d\n",
9417fb1563SFerruh Yigit 			__func__, rc);
9517fb1563SFerruh Yigit 	else
9617fb1563SFerruh Yigit 		cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode,
9717fb1563SFerruh Yigit 			si->si_ofs.mode_size, "xy_mode");
9817fb1563SFerruh Yigit 
9917fb1563SFerruh Yigit 	return rc;
10017fb1563SFerruh Yigit }
10117fb1563SFerruh Yigit 
cyttsp4_handshake(struct cyttsp4 * cd,u8 mode)10217fb1563SFerruh Yigit static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode)
10317fb1563SFerruh Yigit {
10417fb1563SFerruh Yigit 	u8 cmd = mode ^ CY_HST_TOGGLE;
10517fb1563SFerruh Yigit 	int rc;
10617fb1563SFerruh Yigit 
10717fb1563SFerruh Yigit 	/*
10817fb1563SFerruh Yigit 	 * Mode change issued, handshaking now will cause endless mode change
10917fb1563SFerruh Yigit 	 * requests, for sync mode modechange will do same with handshake
11017fb1563SFerruh Yigit 	 * */
11117fb1563SFerruh Yigit 	if (mode & CY_HST_MODE_CHANGE)
11217fb1563SFerruh Yigit 		return 0;
11317fb1563SFerruh Yigit 
11417fb1563SFerruh Yigit 	rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
11517fb1563SFerruh Yigit 	if (rc < 0)
11617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n",
11717fb1563SFerruh Yigit 				__func__, rc);
11817fb1563SFerruh Yigit 
11917fb1563SFerruh Yigit 	return rc;
12017fb1563SFerruh Yigit }
12117fb1563SFerruh Yigit 
cyttsp4_hw_soft_reset(struct cyttsp4 * cd)12217fb1563SFerruh Yigit static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd)
12317fb1563SFerruh Yigit {
12417fb1563SFerruh Yigit 	u8 cmd = CY_HST_RESET;
12517fb1563SFerruh Yigit 	int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
12617fb1563SFerruh Yigit 	if (rc < 0) {
12717fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
12817fb1563SFerruh Yigit 				__func__);
12917fb1563SFerruh Yigit 		return rc;
13017fb1563SFerruh Yigit 	}
13117fb1563SFerruh Yigit 	return 0;
13217fb1563SFerruh Yigit }
13317fb1563SFerruh Yigit 
cyttsp4_hw_hard_reset(struct cyttsp4 * cd)13417fb1563SFerruh Yigit static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd)
13517fb1563SFerruh Yigit {
13617fb1563SFerruh Yigit 	if (cd->cpdata->xres) {
13717fb1563SFerruh Yigit 		cd->cpdata->xres(cd->cpdata, cd->dev);
13817fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__);
13917fb1563SFerruh Yigit 		return 0;
14017fb1563SFerruh Yigit 	}
14117fb1563SFerruh Yigit 	dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
14217fb1563SFerruh Yigit 	return -ENOSYS;
14317fb1563SFerruh Yigit }
14417fb1563SFerruh Yigit 
cyttsp4_hw_reset(struct cyttsp4 * cd)14517fb1563SFerruh Yigit static int cyttsp4_hw_reset(struct cyttsp4 *cd)
14617fb1563SFerruh Yigit {
14717fb1563SFerruh Yigit 	int rc = cyttsp4_hw_hard_reset(cd);
14817fb1563SFerruh Yigit 	if (rc == -ENOSYS)
14917fb1563SFerruh Yigit 		rc = cyttsp4_hw_soft_reset(cd);
15017fb1563SFerruh Yigit 	return rc;
15117fb1563SFerruh Yigit }
15217fb1563SFerruh Yigit 
15317fb1563SFerruh Yigit /*
15417fb1563SFerruh Yigit  * Gets number of bits for a touch filed as parameter,
15517fb1563SFerruh Yigit  * sets maximum value for field which is used as bit mask
15617fb1563SFerruh Yigit  * and returns number of bytes required for that field
15717fb1563SFerruh Yigit  */
cyttsp4_bits_2_bytes(unsigned int nbits,size_t * max)15817fb1563SFerruh Yigit static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max)
15917fb1563SFerruh Yigit {
1600fb82ec0SDan Carpenter 	*max = 1UL << nbits;
16117fb1563SFerruh Yigit 	return (nbits + 7) / 8;
16217fb1563SFerruh Yigit }
16317fb1563SFerruh Yigit 
cyttsp4_si_data_offsets(struct cyttsp4 * cd)16417fb1563SFerruh Yigit static int cyttsp4_si_data_offsets(struct cyttsp4 *cd)
16517fb1563SFerruh Yigit {
16617fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
16717fb1563SFerruh Yigit 	int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data),
16817fb1563SFerruh Yigit 			&si->si_data);
16917fb1563SFerruh Yigit 	if (rc < 0) {
17017fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n",
17117fb1563SFerruh Yigit 			__func__, rc);
17217fb1563SFerruh Yigit 		return rc;
17317fb1563SFerruh Yigit 	}
17417fb1563SFerruh Yigit 
17517fb1563SFerruh Yigit 	/* Print sysinfo data offsets */
17617fb1563SFerruh Yigit 	cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data,
17717fb1563SFerruh Yigit 		       sizeof(si->si_data), "sysinfo_data_offsets");
17817fb1563SFerruh Yigit 
17917fb1563SFerruh Yigit 	/* convert sysinfo data offset bytes into integers */
18017fb1563SFerruh Yigit 
18117fb1563SFerruh Yigit 	si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
18217fb1563SFerruh Yigit 			si->si_data.map_szl);
18317fb1563SFerruh Yigit 	si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
18417fb1563SFerruh Yigit 			si->si_data.map_szl);
18517fb1563SFerruh Yigit 	si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh,
18617fb1563SFerruh Yigit 			si->si_data.cydata_ofsl);
18717fb1563SFerruh Yigit 	si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh,
18817fb1563SFerruh Yigit 			si->si_data.test_ofsl);
18917fb1563SFerruh Yigit 	si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh,
19017fb1563SFerruh Yigit 			si->si_data.pcfg_ofsl);
19117fb1563SFerruh Yigit 	si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh,
19217fb1563SFerruh Yigit 			si->si_data.opcfg_ofsl);
19317fb1563SFerruh Yigit 	si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh,
19417fb1563SFerruh Yigit 			si->si_data.ddata_ofsl);
19517fb1563SFerruh Yigit 	si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh,
19617fb1563SFerruh Yigit 			si->si_data.mdata_ofsl);
19717fb1563SFerruh Yigit 	return rc;
19817fb1563SFerruh Yigit }
19917fb1563SFerruh Yigit 
cyttsp4_si_get_cydata(struct cyttsp4 * cd)20017fb1563SFerruh Yigit static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
20117fb1563SFerruh Yigit {
20217fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
20317fb1563SFerruh Yigit 	int read_offset;
20417fb1563SFerruh Yigit 	int mfgid_sz, calc_mfgid_sz;
20517fb1563SFerruh Yigit 	void *p;
20617fb1563SFerruh Yigit 	int rc;
20717fb1563SFerruh Yigit 
208a2c714e8SVince Kim 	if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
209a2c714e8SVince Kim 		dev_err(cd->dev,
210a2c714e8SVince Kim 			"%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
211a2c714e8SVince Kim 			__func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
212a2c714e8SVince Kim 		return -EINVAL;
213a2c714e8SVince Kim 	}
214a2c714e8SVince Kim 
21517fb1563SFerruh Yigit 	si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
2165b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
21717fb1563SFerruh Yigit 			si->si_ofs.cydata_size);
21817fb1563SFerruh Yigit 
21917fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
22017fb1563SFerruh Yigit 	if (p == NULL) {
221a2c714e8SVince Kim 		dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
222a2c714e8SVince Kim 			__func__);
22317fb1563SFerruh Yigit 		return -ENOMEM;
22417fb1563SFerruh Yigit 	}
22517fb1563SFerruh Yigit 	si->si_ptrs.cydata = p;
22617fb1563SFerruh Yigit 
22717fb1563SFerruh Yigit 	read_offset = si->si_ofs.cydata_ofs;
22817fb1563SFerruh Yigit 
22917fb1563SFerruh Yigit 	/* Read the CYDA registers up to MFGID field */
23017fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, read_offset,
23117fb1563SFerruh Yigit 			offsetof(struct cyttsp4_cydata, mfgid_sz)
23217fb1563SFerruh Yigit 				+ sizeof(si->si_ptrs.cydata->mfgid_sz),
23317fb1563SFerruh Yigit 			si->si_ptrs.cydata);
23417fb1563SFerruh Yigit 	if (rc < 0) {
23517fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read cydata r=%d\n",
23617fb1563SFerruh Yigit 			__func__, rc);
23717fb1563SFerruh Yigit 		return rc;
23817fb1563SFerruh Yigit 	}
23917fb1563SFerruh Yigit 
24017fb1563SFerruh Yigit 	/* Check MFGID size */
24117fb1563SFerruh Yigit 	mfgid_sz = si->si_ptrs.cydata->mfgid_sz;
24217fb1563SFerruh Yigit 	calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata);
24317fb1563SFerruh Yigit 	if (mfgid_sz != calc_mfgid_sz) {
24417fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n",
24517fb1563SFerruh Yigit 			__func__, mfgid_sz, calc_mfgid_sz);
24617fb1563SFerruh Yigit 		return -EINVAL;
24717fb1563SFerruh Yigit 	}
24817fb1563SFerruh Yigit 
24917fb1563SFerruh Yigit 	read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz)
25017fb1563SFerruh Yigit 			+ sizeof(si->si_ptrs.cydata->mfgid_sz);
25117fb1563SFerruh Yigit 
25217fb1563SFerruh Yigit 	/* Read the CYDA registers for MFGID field */
25317fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz,
25417fb1563SFerruh Yigit 			si->si_ptrs.cydata->mfg_id);
25517fb1563SFerruh Yigit 	if (rc < 0) {
25617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read cydata r=%d\n",
25717fb1563SFerruh Yigit 			__func__, rc);
25817fb1563SFerruh Yigit 		return rc;
25917fb1563SFerruh Yigit 	}
26017fb1563SFerruh Yigit 
26117fb1563SFerruh Yigit 	read_offset += si->si_ptrs.cydata->mfgid_sz;
26217fb1563SFerruh Yigit 
26317fb1563SFerruh Yigit 	/* Read the rest of the CYDA registers */
26417fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, read_offset,
26517fb1563SFerruh Yigit 			sizeof(struct cyttsp4_cydata)
26617fb1563SFerruh Yigit 				- offsetof(struct cyttsp4_cydata, cyito_idh),
26717fb1563SFerruh Yigit 			&si->si_ptrs.cydata->cyito_idh);
26817fb1563SFerruh Yigit 	if (rc < 0) {
26917fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read cydata r=%d\n",
27017fb1563SFerruh Yigit 			__func__, rc);
27117fb1563SFerruh Yigit 		return rc;
27217fb1563SFerruh Yigit 	}
27317fb1563SFerruh Yigit 
27417fb1563SFerruh Yigit 	cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata,
27517fb1563SFerruh Yigit 		si->si_ofs.cydata_size, "sysinfo_cydata");
27617fb1563SFerruh Yigit 	return rc;
27717fb1563SFerruh Yigit }
27817fb1563SFerruh Yigit 
cyttsp4_si_get_test_data(struct cyttsp4 * cd)27917fb1563SFerruh Yigit static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
28017fb1563SFerruh Yigit {
28117fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
28217fb1563SFerruh Yigit 	void *p;
28317fb1563SFerruh Yigit 	int rc;
28417fb1563SFerruh Yigit 
285a2c714e8SVince Kim 	if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
286a2c714e8SVince Kim 		dev_err(cd->dev,
287a2c714e8SVince Kim 			"%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
288a2c714e8SVince Kim 			__func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
289a2c714e8SVince Kim 		return -EINVAL;
290a2c714e8SVince Kim 	}
291a2c714e8SVince Kim 
29217fb1563SFerruh Yigit 	si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
29317fb1563SFerruh Yigit 
29417fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
29517fb1563SFerruh Yigit 	if (p == NULL) {
296a2c714e8SVince Kim 		dev_err(cd->dev, "%s: failed to allocate test memory\n",
297a2c714e8SVince Kim 			__func__);
29817fb1563SFerruh Yigit 		return -ENOMEM;
29917fb1563SFerruh Yigit 	}
30017fb1563SFerruh Yigit 	si->si_ptrs.test = p;
30117fb1563SFerruh Yigit 
30217fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size,
30317fb1563SFerruh Yigit 			si->si_ptrs.test);
30417fb1563SFerruh Yigit 	if (rc < 0) {
30517fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read test data r=%d\n",
30617fb1563SFerruh Yigit 			__func__, rc);
30717fb1563SFerruh Yigit 		return rc;
30817fb1563SFerruh Yigit 	}
30917fb1563SFerruh Yigit 
31017fb1563SFerruh Yigit 	cyttsp4_pr_buf(cd->dev, cd->pr_buf,
31117fb1563SFerruh Yigit 		       (u8 *)si->si_ptrs.test, si->si_ofs.test_size,
31217fb1563SFerruh Yigit 		       "sysinfo_test_data");
31317fb1563SFerruh Yigit 	if (si->si_ptrs.test->post_codel &
31417fb1563SFerruh Yigit 	    CY_POST_CODEL_WDG_RST)
31517fb1563SFerruh Yigit 		dev_info(cd->dev, "%s: %s codel=%02X\n",
31617fb1563SFerruh Yigit 			 __func__, "Reset was a WATCHDOG RESET",
31717fb1563SFerruh Yigit 			 si->si_ptrs.test->post_codel);
31817fb1563SFerruh Yigit 
31917fb1563SFerruh Yigit 	if (!(si->si_ptrs.test->post_codel &
32017fb1563SFerruh Yigit 	      CY_POST_CODEL_CFG_DATA_CRC_FAIL))
32117fb1563SFerruh Yigit 		dev_info(cd->dev, "%s: %s codel=%02X\n", __func__,
32217fb1563SFerruh Yigit 			 "Config Data CRC FAIL",
32317fb1563SFerruh Yigit 			 si->si_ptrs.test->post_codel);
32417fb1563SFerruh Yigit 
32517fb1563SFerruh Yigit 	if (!(si->si_ptrs.test->post_codel &
32617fb1563SFerruh Yigit 	      CY_POST_CODEL_PANEL_TEST_FAIL))
32717fb1563SFerruh Yigit 		dev_info(cd->dev, "%s: %s codel=%02X\n",
32817fb1563SFerruh Yigit 			 __func__, "PANEL TEST FAIL",
32917fb1563SFerruh Yigit 			 si->si_ptrs.test->post_codel);
33017fb1563SFerruh Yigit 
33117fb1563SFerruh Yigit 	dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n",
33217fb1563SFerruh Yigit 		 __func__, si->si_ptrs.test->post_codel & 0x08 ?
33317fb1563SFerruh Yigit 		 "ENABLED" : "DISABLED",
33417fb1563SFerruh Yigit 		 si->si_ptrs.test->post_codel);
33517fb1563SFerruh Yigit 	return rc;
33617fb1563SFerruh Yigit }
33717fb1563SFerruh Yigit 
cyttsp4_si_get_pcfg_data(struct cyttsp4 * cd)33817fb1563SFerruh Yigit static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
33917fb1563SFerruh Yigit {
34017fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
34117fb1563SFerruh Yigit 	void *p;
34217fb1563SFerruh Yigit 	int rc;
34317fb1563SFerruh Yigit 
344a2c714e8SVince Kim 	if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
345a2c714e8SVince Kim 		dev_err(cd->dev,
346a2c714e8SVince Kim 			"%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
347a2c714e8SVince Kim 			__func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
348a2c714e8SVince Kim 		return -EINVAL;
349a2c714e8SVince Kim 	}
350a2c714e8SVince Kim 
35117fb1563SFerruh Yigit 	si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
35217fb1563SFerruh Yigit 
35317fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
35417fb1563SFerruh Yigit 	if (p == NULL) {
355a2c714e8SVince Kim 		dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
356a2c714e8SVince Kim 			__func__);
357a2c714e8SVince Kim 		return -ENOMEM;
35817fb1563SFerruh Yigit 	}
35917fb1563SFerruh Yigit 	si->si_ptrs.pcfg = p;
36017fb1563SFerruh Yigit 
36117fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size,
36217fb1563SFerruh Yigit 			si->si_ptrs.pcfg);
36317fb1563SFerruh Yigit 	if (rc < 0) {
36417fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read pcfg data r=%d\n",
36517fb1563SFerruh Yigit 			__func__, rc);
36617fb1563SFerruh Yigit 		return rc;
36717fb1563SFerruh Yigit 	}
36817fb1563SFerruh Yigit 
36917fb1563SFerruh Yigit 	si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh
37017fb1563SFerruh Yigit 			& CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl);
37117fb1563SFerruh Yigit 	si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh
37217fb1563SFerruh Yigit 			& CY_PCFG_ORIGIN_X_MASK);
37317fb1563SFerruh Yigit 	si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh
37417fb1563SFerruh Yigit 			& CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl);
37517fb1563SFerruh Yigit 	si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh
37617fb1563SFerruh Yigit 			& CY_PCFG_ORIGIN_Y_MASK);
37717fb1563SFerruh Yigit 	si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh,
37817fb1563SFerruh Yigit 			si->si_ptrs.pcfg->max_zl);
37917fb1563SFerruh Yigit 
38017fb1563SFerruh Yigit 	cyttsp4_pr_buf(cd->dev, cd->pr_buf,
38117fb1563SFerruh Yigit 		       (u8 *)si->si_ptrs.pcfg,
38217fb1563SFerruh Yigit 		       si->si_ofs.pcfg_size, "sysinfo_pcfg_data");
38317fb1563SFerruh Yigit 	return rc;
38417fb1563SFerruh Yigit }
38517fb1563SFerruh Yigit 
cyttsp4_si_get_opcfg_data(struct cyttsp4 * cd)38617fb1563SFerruh Yigit static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
38717fb1563SFerruh Yigit {
38817fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
38917fb1563SFerruh Yigit 	struct cyttsp4_tch_abs_params *tch;
39017fb1563SFerruh Yigit 	struct cyttsp4_tch_rec_params *tch_old, *tch_new;
39117fb1563SFerruh Yigit 	enum cyttsp4_tch_abs abs;
39217fb1563SFerruh Yigit 	int i;
39317fb1563SFerruh Yigit 	void *p;
39417fb1563SFerruh Yigit 	int rc;
39517fb1563SFerruh Yigit 
396a2c714e8SVince Kim 	if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
397a2c714e8SVince Kim 		dev_err(cd->dev,
398a2c714e8SVince Kim 			"%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
399a2c714e8SVince Kim 			__func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
400a2c714e8SVince Kim 		return -EINVAL;
401a2c714e8SVince Kim 	}
402a2c714e8SVince Kim 
40317fb1563SFerruh Yigit 	si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
40417fb1563SFerruh Yigit 
40517fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
40617fb1563SFerruh Yigit 	if (p == NULL) {
407a2c714e8SVince Kim 		dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
408a2c714e8SVince Kim 			__func__);
409a2c714e8SVince Kim 		return -ENOMEM;
41017fb1563SFerruh Yigit 	}
41117fb1563SFerruh Yigit 	si->si_ptrs.opcfg = p;
41217fb1563SFerruh Yigit 
41317fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size,
41417fb1563SFerruh Yigit 			si->si_ptrs.opcfg);
41517fb1563SFerruh Yigit 	if (rc < 0) {
41617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
41717fb1563SFerruh Yigit 			__func__, rc);
418a2c714e8SVince Kim 		return rc;
41917fb1563SFerruh Yigit 	}
42017fb1563SFerruh Yigit 	si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
42117fb1563SFerruh Yigit 	si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
42217fb1563SFerruh Yigit 	si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) +
42317fb1563SFerruh Yigit 		si->si_ptrs.opcfg->rep_szl;
42417fb1563SFerruh Yigit 	si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns;
42517fb1563SFerruh Yigit 	si->si_ofs.num_btn_regs = (si->si_ofs.num_btns +
42617fb1563SFerruh Yigit 		CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG;
42717fb1563SFerruh Yigit 	si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs;
42817fb1563SFerruh Yigit 	si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0;
42917fb1563SFerruh Yigit 	si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs &
43017fb1563SFerruh Yigit 		CY_BYTE_OFS_MASK;
43117fb1563SFerruh Yigit 	si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size &
43217fb1563SFerruh Yigit 		CY_BYTE_OFS_MASK;
43317fb1563SFerruh Yigit 
43417fb1563SFerruh Yigit 	/* Get the old touch fields */
43517fb1563SFerruh Yigit 	for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) {
43617fb1563SFerruh Yigit 		tch = &si->si_ofs.tch_abs[abs];
43717fb1563SFerruh Yigit 		tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs];
43817fb1563SFerruh Yigit 
43917fb1563SFerruh Yigit 		tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK;
44017fb1563SFerruh Yigit 		tch->size = cyttsp4_bits_2_bytes(tch_old->size,
44117fb1563SFerruh Yigit 						 &tch->max);
44217fb1563SFerruh Yigit 		tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
44317fb1563SFerruh Yigit 	}
44417fb1563SFerruh Yigit 
44517fb1563SFerruh Yigit 	/* button fields */
44617fb1563SFerruh Yigit 	si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size;
44717fb1563SFerruh Yigit 	si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs;
44817fb1563SFerruh Yigit 	si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size;
44917fb1563SFerruh Yigit 
45017fb1563SFerruh Yigit 	if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
45117fb1563SFerruh Yigit 		/* Get the extended touch fields */
45217fb1563SFerruh Yigit 		for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) {
45317fb1563SFerruh Yigit 			tch = &si->si_ofs.tch_abs[abs];
45417fb1563SFerruh Yigit 			tch_new = &si->si_ptrs.opcfg->tch_rec_new[i];
45517fb1563SFerruh Yigit 
45617fb1563SFerruh Yigit 			tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK;
45717fb1563SFerruh Yigit 			tch->size = cyttsp4_bits_2_bytes(tch_new->size,
45817fb1563SFerruh Yigit 							 &tch->max);
45917fb1563SFerruh Yigit 			tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
46017fb1563SFerruh Yigit 		}
46117fb1563SFerruh Yigit 	}
46217fb1563SFerruh Yigit 
46317fb1563SFerruh Yigit 	for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) {
46417fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__,
46517fb1563SFerruh Yigit 			cyttsp4_tch_abs_string[abs]);
4665b5e0928SAlexey Dobriyan 		dev_dbg(cd->dev, "%s:     ofs =%2zd\n", __func__,
46717fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].ofs);
4685b5e0928SAlexey Dobriyan 		dev_dbg(cd->dev, "%s:     siz =%2zd\n", __func__,
46917fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].size);
4705b5e0928SAlexey Dobriyan 		dev_dbg(cd->dev, "%s:     max =%2zd\n", __func__,
47117fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].max);
4725b5e0928SAlexey Dobriyan 		dev_dbg(cd->dev, "%s:     bofs=%2zd\n", __func__,
47317fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].bofs);
47417fb1563SFerruh Yigit 	}
47517fb1563SFerruh Yigit 
47617fb1563SFerruh Yigit 	si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1;
47717fb1563SFerruh Yigit 	si->si_ofs.data_size = si->si_ofs.max_tchs *
47817fb1563SFerruh Yigit 		si->si_ptrs.opcfg->tch_rec_size;
47917fb1563SFerruh Yigit 
48017fb1563SFerruh Yigit 	cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
48117fb1563SFerruh Yigit 		si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
48217fb1563SFerruh Yigit 
483a2c714e8SVince Kim 	return 0;
48417fb1563SFerruh Yigit }
48517fb1563SFerruh Yigit 
cyttsp4_si_get_ddata(struct cyttsp4 * cd)48617fb1563SFerruh Yigit static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
48717fb1563SFerruh Yigit {
48817fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
48917fb1563SFerruh Yigit 	void *p;
49017fb1563SFerruh Yigit 	int rc;
49117fb1563SFerruh Yigit 
49217fb1563SFerruh Yigit 	si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs;
49317fb1563SFerruh Yigit 
49417fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL);
49517fb1563SFerruh Yigit 	if (p == NULL) {
49617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__);
49717fb1563SFerruh Yigit 		return -ENOMEM;
49817fb1563SFerruh Yigit 	}
49917fb1563SFerruh Yigit 	si->si_ptrs.ddata = p;
50017fb1563SFerruh Yigit 
50117fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size,
50217fb1563SFerruh Yigit 			si->si_ptrs.ddata);
50317fb1563SFerruh Yigit 	if (rc < 0)
50417fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read ddata data r=%d\n",
50517fb1563SFerruh Yigit 			__func__, rc);
50617fb1563SFerruh Yigit 	else
50717fb1563SFerruh Yigit 		cyttsp4_pr_buf(cd->dev, cd->pr_buf,
50817fb1563SFerruh Yigit 			       (u8 *)si->si_ptrs.ddata,
50917fb1563SFerruh Yigit 			       si->si_ofs.ddata_size, "sysinfo_ddata");
51017fb1563SFerruh Yigit 	return rc;
51117fb1563SFerruh Yigit }
51217fb1563SFerruh Yigit 
cyttsp4_si_get_mdata(struct cyttsp4 * cd)51317fb1563SFerruh Yigit static int cyttsp4_si_get_mdata(struct cyttsp4 *cd)
51417fb1563SFerruh Yigit {
51517fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
51617fb1563SFerruh Yigit 	void *p;
51717fb1563SFerruh Yigit 	int rc;
51817fb1563SFerruh Yigit 
51917fb1563SFerruh Yigit 	si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs;
52017fb1563SFerruh Yigit 
52117fb1563SFerruh Yigit 	p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL);
52217fb1563SFerruh Yigit 	if (p == NULL) {
52317fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__);
52417fb1563SFerruh Yigit 		return -ENOMEM;
52517fb1563SFerruh Yigit 	}
52617fb1563SFerruh Yigit 	si->si_ptrs.mdata = p;
52717fb1563SFerruh Yigit 
52817fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size,
52917fb1563SFerruh Yigit 			si->si_ptrs.mdata);
53017fb1563SFerruh Yigit 	if (rc < 0)
53117fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail read mdata data r=%d\n",
53217fb1563SFerruh Yigit 			__func__, rc);
53317fb1563SFerruh Yigit 	else
53417fb1563SFerruh Yigit 		cyttsp4_pr_buf(cd->dev, cd->pr_buf,
53517fb1563SFerruh Yigit 			       (u8 *)si->si_ptrs.mdata,
53617fb1563SFerruh Yigit 			       si->si_ofs.mdata_size, "sysinfo_mdata");
53717fb1563SFerruh Yigit 	return rc;
53817fb1563SFerruh Yigit }
53917fb1563SFerruh Yigit 
cyttsp4_si_get_btn_data(struct cyttsp4 * cd)54017fb1563SFerruh Yigit static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd)
54117fb1563SFerruh Yigit {
54217fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
54317fb1563SFerruh Yigit 	int btn;
54417fb1563SFerruh Yigit 	int num_defined_keys;
54517fb1563SFerruh Yigit 	u16 *key_table;
54617fb1563SFerruh Yigit 	void *p;
54717fb1563SFerruh Yigit 	int rc = 0;
54817fb1563SFerruh Yigit 
54917fb1563SFerruh Yigit 	if (si->si_ofs.num_btns) {
55017fb1563SFerruh Yigit 		si->si_ofs.btn_keys_size = si->si_ofs.num_btns *
55117fb1563SFerruh Yigit 			sizeof(struct cyttsp4_btn);
55217fb1563SFerruh Yigit 
55317fb1563SFerruh Yigit 		p = krealloc(si->btn, si->si_ofs.btn_keys_size,
55417fb1563SFerruh Yigit 				GFP_KERNEL|__GFP_ZERO);
55517fb1563SFerruh Yigit 		if (p == NULL) {
55617fb1563SFerruh Yigit 			dev_err(cd->dev, "%s: %s\n", __func__,
55717fb1563SFerruh Yigit 				"fail alloc btn_keys memory");
55817fb1563SFerruh Yigit 			return -ENOMEM;
55917fb1563SFerruh Yigit 		}
56017fb1563SFerruh Yigit 		si->btn = p;
56117fb1563SFerruh Yigit 
56217fb1563SFerruh Yigit 		if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL)
56317fb1563SFerruh Yigit 			num_defined_keys = 0;
56417fb1563SFerruh Yigit 		else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL)
56517fb1563SFerruh Yigit 			num_defined_keys = 0;
56617fb1563SFerruh Yigit 		else
56717fb1563SFerruh Yigit 			num_defined_keys = cd->cpdata->sett
56817fb1563SFerruh Yigit 				[CY_IC_GRPNUM_BTN_KEYS]->size;
56917fb1563SFerruh Yigit 
57017fb1563SFerruh Yigit 		for (btn = 0; btn < si->si_ofs.num_btns &&
57117fb1563SFerruh Yigit 			btn < num_defined_keys; btn++) {
57217fb1563SFerruh Yigit 			key_table = (u16 *)cd->cpdata->sett
57317fb1563SFerruh Yigit 				[CY_IC_GRPNUM_BTN_KEYS]->data;
57417fb1563SFerruh Yigit 			si->btn[btn].key_code = key_table[btn];
57517fb1563SFerruh Yigit 			si->btn[btn].state = CY_BTN_RELEASED;
57617fb1563SFerruh Yigit 			si->btn[btn].enabled = true;
57717fb1563SFerruh Yigit 		}
57817fb1563SFerruh Yigit 		for (; btn < si->si_ofs.num_btns; btn++) {
57917fb1563SFerruh Yigit 			si->btn[btn].key_code = KEY_RESERVED;
58017fb1563SFerruh Yigit 			si->btn[btn].state = CY_BTN_RELEASED;
58117fb1563SFerruh Yigit 			si->btn[btn].enabled = true;
58217fb1563SFerruh Yigit 		}
58317fb1563SFerruh Yigit 
58417fb1563SFerruh Yigit 		return rc;
58517fb1563SFerruh Yigit 	}
58617fb1563SFerruh Yigit 
58717fb1563SFerruh Yigit 	si->si_ofs.btn_keys_size = 0;
58817fb1563SFerruh Yigit 	kfree(si->btn);
58917fb1563SFerruh Yigit 	si->btn = NULL;
59017fb1563SFerruh Yigit 	return rc;
59117fb1563SFerruh Yigit }
59217fb1563SFerruh Yigit 
cyttsp4_si_get_op_data_ptrs(struct cyttsp4 * cd)59317fb1563SFerruh Yigit static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd)
59417fb1563SFerruh Yigit {
59517fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
59617fb1563SFerruh Yigit 	void *p;
59717fb1563SFerruh Yigit 
59817fb1563SFerruh Yigit 	p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO);
59917fb1563SFerruh Yigit 	if (p == NULL)
60017fb1563SFerruh Yigit 		return -ENOMEM;
60117fb1563SFerruh Yigit 	si->xy_mode = p;
60217fb1563SFerruh Yigit 
60317fb1563SFerruh Yigit 	p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO);
60417fb1563SFerruh Yigit 	if (p == NULL)
60517fb1563SFerruh Yigit 		return -ENOMEM;
60617fb1563SFerruh Yigit 	si->xy_data = p;
60717fb1563SFerruh Yigit 
60817fb1563SFerruh Yigit 	p = krealloc(si->btn_rec_data,
60917fb1563SFerruh Yigit 			si->si_ofs.btn_rec_size * si->si_ofs.num_btns,
61017fb1563SFerruh Yigit 			GFP_KERNEL|__GFP_ZERO);
61117fb1563SFerruh Yigit 	if (p == NULL)
61217fb1563SFerruh Yigit 		return -ENOMEM;
61317fb1563SFerruh Yigit 	si->btn_rec_data = p;
61417fb1563SFerruh Yigit 
61517fb1563SFerruh Yigit 	return 0;
61617fb1563SFerruh Yigit }
61717fb1563SFerruh Yigit 
cyttsp4_si_put_log_data(struct cyttsp4 * cd)61817fb1563SFerruh Yigit static void cyttsp4_si_put_log_data(struct cyttsp4 *cd)
61917fb1563SFerruh Yigit {
62017fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
6215b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: cydata_ofs =%4zd siz=%4zd\n", __func__,
62217fb1563SFerruh Yigit 		si->si_ofs.cydata_ofs, si->si_ofs.cydata_size);
6235b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: test_ofs   =%4zd siz=%4zd\n", __func__,
62417fb1563SFerruh Yigit 		si->si_ofs.test_ofs, si->si_ofs.test_size);
6255b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: pcfg_ofs   =%4zd siz=%4zd\n", __func__,
62617fb1563SFerruh Yigit 		si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size);
6275b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: opcfg_ofs  =%4zd siz=%4zd\n", __func__,
62817fb1563SFerruh Yigit 		si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size);
6295b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: ddata_ofs  =%4zd siz=%4zd\n", __func__,
63017fb1563SFerruh Yigit 		si->si_ofs.ddata_ofs, si->si_ofs.ddata_size);
6315b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: mdata_ofs  =%4zd siz=%4zd\n", __func__,
63217fb1563SFerruh Yigit 		si->si_ofs.mdata_ofs, si->si_ofs.mdata_size);
63317fb1563SFerruh Yigit 
6345b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: cmd_ofs       =%4zd\n", __func__,
63517fb1563SFerruh Yigit 		si->si_ofs.cmd_ofs);
6365b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: rep_ofs       =%4zd\n", __func__,
63717fb1563SFerruh Yigit 		si->si_ofs.rep_ofs);
6385b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: rep_sz        =%4zd\n", __func__,
63917fb1563SFerruh Yigit 		si->si_ofs.rep_sz);
6405b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: num_btns      =%4zd\n", __func__,
64117fb1563SFerruh Yigit 		si->si_ofs.num_btns);
6425b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: num_btn_regs  =%4zd\n", __func__,
64317fb1563SFerruh Yigit 		si->si_ofs.num_btn_regs);
6445b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: tt_stat_ofs   =%4zd\n", __func__,
64517fb1563SFerruh Yigit 		si->si_ofs.tt_stat_ofs);
6465b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: tch_rec_size  =%4zd\n", __func__,
64717fb1563SFerruh Yigit 		si->si_ofs.tch_rec_size);
6485b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: max_tchs      =%4zd\n", __func__,
64917fb1563SFerruh Yigit 		si->si_ofs.max_tchs);
6505b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: mode_size     =%4zd\n", __func__,
65117fb1563SFerruh Yigit 		si->si_ofs.mode_size);
6525b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: data_size     =%4zd\n", __func__,
65317fb1563SFerruh Yigit 		si->si_ofs.data_size);
6545b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: map_sz        =%4zd\n", __func__,
65517fb1563SFerruh Yigit 		si->si_ofs.map_sz);
65617fb1563SFerruh Yigit 
6575b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: btn_rec_size   =%2zd\n", __func__,
65817fb1563SFerruh Yigit 		si->si_ofs.btn_rec_size);
6595b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: btn_diff_ofs   =%2zd\n", __func__,
66017fb1563SFerruh Yigit 		si->si_ofs.btn_diff_ofs);
6615b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: btn_diff_size  =%2zd\n", __func__,
66217fb1563SFerruh Yigit 		si->si_ofs.btn_diff_size);
66317fb1563SFerruh Yigit 
6645b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: max_x    = 0x%04zX (%zd)\n", __func__,
66517fb1563SFerruh Yigit 		si->si_ofs.max_x, si->si_ofs.max_x);
6665b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: x_origin = %zd (%s)\n", __func__,
66717fb1563SFerruh Yigit 		si->si_ofs.x_origin,
66817fb1563SFerruh Yigit 		si->si_ofs.x_origin == CY_NORMAL_ORIGIN ?
66917fb1563SFerruh Yigit 		"left corner" : "right corner");
6705b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: max_y    = 0x%04zX (%zd)\n", __func__,
67117fb1563SFerruh Yigit 		si->si_ofs.max_y, si->si_ofs.max_y);
6725b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: y_origin = %zd (%s)\n", __func__,
67317fb1563SFerruh Yigit 		si->si_ofs.y_origin,
67417fb1563SFerruh Yigit 		si->si_ofs.y_origin == CY_NORMAL_ORIGIN ?
67517fb1563SFerruh Yigit 		"upper corner" : "lower corner");
6765b5e0928SAlexey Dobriyan 	dev_dbg(cd->dev, "%s: max_p    = 0x%04zX (%zd)\n", __func__,
67717fb1563SFerruh Yigit 		si->si_ofs.max_p, si->si_ofs.max_p);
67817fb1563SFerruh Yigit 
67917fb1563SFerruh Yigit 	dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__,
68017fb1563SFerruh Yigit 		si->xy_mode, si->xy_data);
68117fb1563SFerruh Yigit }
68217fb1563SFerruh Yigit 
cyttsp4_get_sysinfo_regs(struct cyttsp4 * cd)68317fb1563SFerruh Yigit static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd)
68417fb1563SFerruh Yigit {
68517fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
68617fb1563SFerruh Yigit 	int rc;
68717fb1563SFerruh Yigit 
68817fb1563SFerruh Yigit 	rc = cyttsp4_si_data_offsets(cd);
68917fb1563SFerruh Yigit 	if (rc < 0)
69017fb1563SFerruh Yigit 		return rc;
69117fb1563SFerruh Yigit 
69217fb1563SFerruh Yigit 	rc = cyttsp4_si_get_cydata(cd);
69317fb1563SFerruh Yigit 	if (rc < 0)
69417fb1563SFerruh Yigit 		return rc;
69517fb1563SFerruh Yigit 
69617fb1563SFerruh Yigit 	rc = cyttsp4_si_get_test_data(cd);
69717fb1563SFerruh Yigit 	if (rc < 0)
69817fb1563SFerruh Yigit 		return rc;
69917fb1563SFerruh Yigit 
70017fb1563SFerruh Yigit 	rc = cyttsp4_si_get_pcfg_data(cd);
70117fb1563SFerruh Yigit 	if (rc < 0)
70217fb1563SFerruh Yigit 		return rc;
70317fb1563SFerruh Yigit 
70417fb1563SFerruh Yigit 	rc = cyttsp4_si_get_opcfg_data(cd);
70517fb1563SFerruh Yigit 	if (rc < 0)
70617fb1563SFerruh Yigit 		return rc;
70717fb1563SFerruh Yigit 
70817fb1563SFerruh Yigit 	rc = cyttsp4_si_get_ddata(cd);
70917fb1563SFerruh Yigit 	if (rc < 0)
71017fb1563SFerruh Yigit 		return rc;
71117fb1563SFerruh Yigit 
71217fb1563SFerruh Yigit 	rc = cyttsp4_si_get_mdata(cd);
71317fb1563SFerruh Yigit 	if (rc < 0)
71417fb1563SFerruh Yigit 		return rc;
71517fb1563SFerruh Yigit 
71617fb1563SFerruh Yigit 	rc = cyttsp4_si_get_btn_data(cd);
71717fb1563SFerruh Yigit 	if (rc < 0)
71817fb1563SFerruh Yigit 		return rc;
71917fb1563SFerruh Yigit 
72017fb1563SFerruh Yigit 	rc = cyttsp4_si_get_op_data_ptrs(cd);
72117fb1563SFerruh Yigit 	if (rc < 0) {
72217fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: failed to get_op_data\n",
72317fb1563SFerruh Yigit 			__func__);
72417fb1563SFerruh Yigit 		return rc;
72517fb1563SFerruh Yigit 	}
72617fb1563SFerruh Yigit 
72717fb1563SFerruh Yigit 	cyttsp4_si_put_log_data(cd);
72817fb1563SFerruh Yigit 
72917fb1563SFerruh Yigit 	/* provide flow control handshake */
73017fb1563SFerruh Yigit 	rc = cyttsp4_handshake(cd, si->si_data.hst_mode);
73117fb1563SFerruh Yigit 	if (rc < 0)
73217fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n",
73317fb1563SFerruh Yigit 			__func__);
73417fb1563SFerruh Yigit 
73517fb1563SFerruh Yigit 	si->ready = true;
73617fb1563SFerruh Yigit 	return rc;
73717fb1563SFerruh Yigit }
73817fb1563SFerruh Yigit 
cyttsp4_queue_startup_(struct cyttsp4 * cd)73917fb1563SFerruh Yigit static void cyttsp4_queue_startup_(struct cyttsp4 *cd)
74017fb1563SFerruh Yigit {
74117fb1563SFerruh Yigit 	if (cd->startup_state == STARTUP_NONE) {
74217fb1563SFerruh Yigit 		cd->startup_state = STARTUP_QUEUED;
74317fb1563SFerruh Yigit 		schedule_work(&cd->startup_work);
74417fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__);
74517fb1563SFerruh Yigit 	} else {
74617fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__,
74717fb1563SFerruh Yigit 			cd->startup_state);
74817fb1563SFerruh Yigit 	}
74917fb1563SFerruh Yigit }
75017fb1563SFerruh Yigit 
cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data * md,int max_slots)75117fb1563SFerruh Yigit static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md,
75217fb1563SFerruh Yigit 		int max_slots)
75317fb1563SFerruh Yigit {
75417fb1563SFerruh Yigit 	int t;
75517fb1563SFerruh Yigit 
75617fb1563SFerruh Yigit 	if (md->num_prv_tch == 0)
75717fb1563SFerruh Yigit 		return;
75817fb1563SFerruh Yigit 
75917fb1563SFerruh Yigit 	for (t = 0; t < max_slots; t++) {
76017fb1563SFerruh Yigit 		input_mt_slot(md->input, t);
7615fc70e35SJiada Wang 		input_mt_report_slot_inactive(md->input);
76217fb1563SFerruh Yigit 	}
76317fb1563SFerruh Yigit }
76417fb1563SFerruh Yigit 
cyttsp4_lift_all(struct cyttsp4_mt_data * md)76517fb1563SFerruh Yigit static void cyttsp4_lift_all(struct cyttsp4_mt_data *md)
76617fb1563SFerruh Yigit {
76717fb1563SFerruh Yigit 	if (!md->si)
76817fb1563SFerruh Yigit 		return;
76917fb1563SFerruh Yigit 
77017fb1563SFerruh Yigit 	if (md->num_prv_tch != 0) {
77117fb1563SFerruh Yigit 		cyttsp4_report_slot_liftoff(md,
77217fb1563SFerruh Yigit 				md->si->si_ofs.tch_abs[CY_TCH_T].max);
77317fb1563SFerruh Yigit 		input_sync(md->input);
77417fb1563SFerruh Yigit 		md->num_prv_tch = 0;
77517fb1563SFerruh Yigit 	}
77617fb1563SFerruh Yigit }
77717fb1563SFerruh Yigit 
cyttsp4_get_touch_axis(struct cyttsp4_mt_data * md,int * axis,int size,int max,u8 * xy_data,int bofs)77817fb1563SFerruh Yigit static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md,
77917fb1563SFerruh Yigit 	int *axis, int size, int max, u8 *xy_data, int bofs)
78017fb1563SFerruh Yigit {
78117fb1563SFerruh Yigit 	int nbyte;
78217fb1563SFerruh Yigit 	int next;
78317fb1563SFerruh Yigit 
78417fb1563SFerruh Yigit 	for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
78517fb1563SFerruh Yigit 		dev_vdbg(&md->input->dev,
78617fb1563SFerruh Yigit 			"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
78717fb1563SFerruh Yigit 			" xy_data[%d]=%02X(%d) bofs=%d\n",
78817fb1563SFerruh Yigit 			__func__, *axis, *axis, size, max, xy_data, next,
78917fb1563SFerruh Yigit 			xy_data[next], xy_data[next], bofs);
79017fb1563SFerruh Yigit 		*axis = (*axis * 256) + (xy_data[next] >> bofs);
79117fb1563SFerruh Yigit 		next++;
79217fb1563SFerruh Yigit 	}
79317fb1563SFerruh Yigit 
79417fb1563SFerruh Yigit 	*axis &= max - 1;
79517fb1563SFerruh Yigit 
79617fb1563SFerruh Yigit 	dev_vdbg(&md->input->dev,
79717fb1563SFerruh Yigit 		"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
79817fb1563SFerruh Yigit 		" xy_data[%d]=%02X(%d)\n",
79917fb1563SFerruh Yigit 		__func__, *axis, *axis, size, max, xy_data, next,
80017fb1563SFerruh Yigit 		xy_data[next], xy_data[next]);
80117fb1563SFerruh Yigit }
80217fb1563SFerruh Yigit 
cyttsp4_get_touch(struct cyttsp4_mt_data * md,struct cyttsp4_touch * touch,u8 * xy_data)80317fb1563SFerruh Yigit static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
80417fb1563SFerruh Yigit 	struct cyttsp4_touch *touch, u8 *xy_data)
80517fb1563SFerruh Yigit {
80617fb1563SFerruh Yigit 	struct device *dev = &md->input->dev;
80717fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = md->si;
80817fb1563SFerruh Yigit 	enum cyttsp4_tch_abs abs;
80917fb1563SFerruh Yigit 	bool flipped;
81017fb1563SFerruh Yigit 
81117fb1563SFerruh Yigit 	for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
81217fb1563SFerruh Yigit 		cyttsp4_get_touch_axis(md, &touch->abs[abs],
81317fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].size,
81417fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].max,
81517fb1563SFerruh Yigit 			xy_data + si->si_ofs.tch_abs[abs].ofs,
81617fb1563SFerruh Yigit 			si->si_ofs.tch_abs[abs].bofs);
81717fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
81817fb1563SFerruh Yigit 			cyttsp4_tch_abs_string[abs],
81917fb1563SFerruh Yigit 			touch->abs[abs], touch->abs[abs]);
82017fb1563SFerruh Yigit 	}
82117fb1563SFerruh Yigit 
82217fb1563SFerruh Yigit 	if (md->pdata->flags & CY_FLAG_FLIP) {
823cf99289dSFabian Frederick 		swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
82417fb1563SFerruh Yigit 		flipped = true;
82517fb1563SFerruh Yigit 	} else
82617fb1563SFerruh Yigit 		flipped = false;
82717fb1563SFerruh Yigit 
82817fb1563SFerruh Yigit 	if (md->pdata->flags & CY_FLAG_INV_X) {
82917fb1563SFerruh Yigit 		if (flipped)
83017fb1563SFerruh Yigit 			touch->abs[CY_TCH_X] = md->si->si_ofs.max_y -
83117fb1563SFerruh Yigit 				touch->abs[CY_TCH_X];
83217fb1563SFerruh Yigit 		else
83317fb1563SFerruh Yigit 			touch->abs[CY_TCH_X] = md->si->si_ofs.max_x -
83417fb1563SFerruh Yigit 				touch->abs[CY_TCH_X];
83517fb1563SFerruh Yigit 	}
83617fb1563SFerruh Yigit 	if (md->pdata->flags & CY_FLAG_INV_Y) {
83717fb1563SFerruh Yigit 		if (flipped)
83817fb1563SFerruh Yigit 			touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x -
83917fb1563SFerruh Yigit 				touch->abs[CY_TCH_Y];
84017fb1563SFerruh Yigit 		else
84117fb1563SFerruh Yigit 			touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y -
84217fb1563SFerruh Yigit 				touch->abs[CY_TCH_Y];
84317fb1563SFerruh Yigit 	}
84417fb1563SFerruh Yigit 
84517fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
84617fb1563SFerruh Yigit 		__func__, flipped ? "true" : "false",
84717fb1563SFerruh Yigit 		md->pdata->flags & CY_FLAG_INV_X ? "true" : "false",
84817fb1563SFerruh Yigit 		md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false",
84917fb1563SFerruh Yigit 		touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
85017fb1563SFerruh Yigit 		touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
85117fb1563SFerruh Yigit }
85217fb1563SFerruh Yigit 
cyttsp4_final_sync(struct input_dev * input,int max_slots,int * ids)85317fb1563SFerruh Yigit static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids)
85417fb1563SFerruh Yigit {
85517fb1563SFerruh Yigit 	int t;
85617fb1563SFerruh Yigit 
85717fb1563SFerruh Yigit 	for (t = 0; t < max_slots; t++) {
85817fb1563SFerruh Yigit 		if (ids[t])
85917fb1563SFerruh Yigit 			continue;
86017fb1563SFerruh Yigit 		input_mt_slot(input, t);
8615fc70e35SJiada Wang 		input_mt_report_slot_inactive(input);
86217fb1563SFerruh Yigit 	}
86317fb1563SFerruh Yigit 
86417fb1563SFerruh Yigit 	input_sync(input);
86517fb1563SFerruh Yigit }
86617fb1563SFerruh Yigit 
cyttsp4_get_mt_touches(struct cyttsp4_mt_data * md,int num_cur_tch)86717fb1563SFerruh Yigit static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
86817fb1563SFerruh Yigit {
86917fb1563SFerruh Yigit 	struct device *dev = &md->input->dev;
87017fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = md->si;
87117fb1563SFerruh Yigit 	struct cyttsp4_touch tch;
87217fb1563SFerruh Yigit 	int sig;
87317fb1563SFerruh Yigit 	int i, j, t = 0;
87417fb1563SFerruh Yigit 	int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
87517fb1563SFerruh Yigit 
87617fb1563SFerruh Yigit 	memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int));
87717fb1563SFerruh Yigit 	for (i = 0; i < num_cur_tch; i++) {
87817fb1563SFerruh Yigit 		cyttsp4_get_touch(md, &tch, si->xy_data +
87917fb1563SFerruh Yigit 			(i * si->si_ofs.tch_rec_size));
88017fb1563SFerruh Yigit 		if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs
88117fb1563SFerruh Yigit 			[(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) ||
88217fb1563SFerruh Yigit 			(tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs
88317fb1563SFerruh Yigit 			[(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) {
88417fb1563SFerruh Yigit 			dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
88517fb1563SFerruh Yigit 				__func__, i, tch.abs[CY_TCH_T],
88617fb1563SFerruh Yigit 				md->pdata->frmwrk->abs[(CY_ABS_ID_OST *
88717fb1563SFerruh Yigit 				CY_NUM_ABS_SET) + CY_MAX_OST]);
88817fb1563SFerruh Yigit 			continue;
88917fb1563SFerruh Yigit 		}
89017fb1563SFerruh Yigit 
89117fb1563SFerruh Yigit 		/* use 0 based track id's */
89217fb1563SFerruh Yigit 		sig = md->pdata->frmwrk->abs
89317fb1563SFerruh Yigit 			[(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0];
89417fb1563SFerruh Yigit 		if (sig != CY_IGNORE_VALUE) {
89517fb1563SFerruh Yigit 			t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs
89617fb1563SFerruh Yigit 				[(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST];
89717fb1563SFerruh Yigit 			if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) {
89817fb1563SFerruh Yigit 				dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
89917fb1563SFerruh Yigit 					__func__, t, tch.abs[CY_TCH_E]);
90017fb1563SFerruh Yigit 				goto cyttsp4_get_mt_touches_pr_tch;
90117fb1563SFerruh Yigit 			}
90217fb1563SFerruh Yigit 			input_mt_slot(md->input, t);
90317fb1563SFerruh Yigit 			input_mt_report_slot_state(md->input, MT_TOOL_FINGER,
90417fb1563SFerruh Yigit 					true);
90517fb1563SFerruh Yigit 			ids[t] = true;
90617fb1563SFerruh Yigit 		}
90717fb1563SFerruh Yigit 
90817fb1563SFerruh Yigit 		/* all devices: position and pressure fields */
90917fb1563SFerruh Yigit 		for (j = 0; j <= CY_ABS_W_OST; j++) {
91017fb1563SFerruh Yigit 			sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) *
91117fb1563SFerruh Yigit 				CY_NUM_ABS_SET) + 0];
91217fb1563SFerruh Yigit 			if (sig != CY_IGNORE_VALUE)
91317fb1563SFerruh Yigit 				input_report_abs(md->input, sig,
91417fb1563SFerruh Yigit 					tch.abs[CY_TCH_X + j]);
91517fb1563SFerruh Yigit 		}
91617fb1563SFerruh Yigit 		if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
91717fb1563SFerruh Yigit 			/*
91817fb1563SFerruh Yigit 			 * TMA400 size and orientation fields:
91917fb1563SFerruh Yigit 			 * if pressure is non-zero and major touch
92017fb1563SFerruh Yigit 			 * signal is zero, then set major and minor touch
92117fb1563SFerruh Yigit 			 * signals to minimum non-zero value
92217fb1563SFerruh Yigit 			 */
92317fb1563SFerruh Yigit 			if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0)
92417fb1563SFerruh Yigit 				tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1;
92517fb1563SFerruh Yigit 
92617fb1563SFerruh Yigit 			/* Get the extended touch fields */
92717fb1563SFerruh Yigit 			for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
92817fb1563SFerruh Yigit 				sig = md->pdata->frmwrk->abs
92917fb1563SFerruh Yigit 					[((CY_ABS_MAJ_OST + j) *
93017fb1563SFerruh Yigit 					CY_NUM_ABS_SET) + 0];
93117fb1563SFerruh Yigit 				if (sig != CY_IGNORE_VALUE)
93217fb1563SFerruh Yigit 					input_report_abs(md->input, sig,
93317fb1563SFerruh Yigit 						tch.abs[CY_TCH_MAJ + j]);
93417fb1563SFerruh Yigit 			}
93517fb1563SFerruh Yigit 		}
93617fb1563SFerruh Yigit 
93717fb1563SFerruh Yigit cyttsp4_get_mt_touches_pr_tch:
93817fb1563SFerruh Yigit 		if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE)
93917fb1563SFerruh Yigit 			dev_dbg(dev,
94017fb1563SFerruh Yigit 				"%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n",
94117fb1563SFerruh Yigit 				__func__, t,
94217fb1563SFerruh Yigit 				tch.abs[CY_TCH_X],
94317fb1563SFerruh Yigit 				tch.abs[CY_TCH_Y],
94417fb1563SFerruh Yigit 				tch.abs[CY_TCH_P],
94517fb1563SFerruh Yigit 				tch.abs[CY_TCH_MAJ],
94617fb1563SFerruh Yigit 				tch.abs[CY_TCH_MIN],
94717fb1563SFerruh Yigit 				tch.abs[CY_TCH_OR],
94817fb1563SFerruh Yigit 				tch.abs[CY_TCH_E]);
94917fb1563SFerruh Yigit 		else
95017fb1563SFerruh Yigit 			dev_dbg(dev,
95117fb1563SFerruh Yigit 				"%s: t=%d x=%d y=%d z=%d e=%d\n", __func__,
95217fb1563SFerruh Yigit 				t,
95317fb1563SFerruh Yigit 				tch.abs[CY_TCH_X],
95417fb1563SFerruh Yigit 				tch.abs[CY_TCH_Y],
95517fb1563SFerruh Yigit 				tch.abs[CY_TCH_P],
95617fb1563SFerruh Yigit 				tch.abs[CY_TCH_E]);
95717fb1563SFerruh Yigit 	}
95817fb1563SFerruh Yigit 
95917fb1563SFerruh Yigit 	cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids);
96017fb1563SFerruh Yigit 
96117fb1563SFerruh Yigit 	md->num_prv_tch = num_cur_tch;
96217fb1563SFerruh Yigit 
96317fb1563SFerruh Yigit 	return;
96417fb1563SFerruh Yigit }
96517fb1563SFerruh Yigit 
96617fb1563SFerruh Yigit /* read xy_data for all current touches */
cyttsp4_xy_worker(struct cyttsp4 * cd)96717fb1563SFerruh Yigit static int cyttsp4_xy_worker(struct cyttsp4 *cd)
96817fb1563SFerruh Yigit {
96917fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
97017fb1563SFerruh Yigit 	struct device *dev = &md->input->dev;
97117fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = md->si;
97217fb1563SFerruh Yigit 	u8 num_cur_tch;
97317fb1563SFerruh Yigit 	u8 hst_mode;
97417fb1563SFerruh Yigit 	u8 rep_len;
97517fb1563SFerruh Yigit 	u8 rep_stat;
97617fb1563SFerruh Yigit 	u8 tt_stat;
97717fb1563SFerruh Yigit 	int rc = 0;
97817fb1563SFerruh Yigit 
97917fb1563SFerruh Yigit 	/*
98017fb1563SFerruh Yigit 	 * Get event data from cyttsp4 device.
98117fb1563SFerruh Yigit 	 * The event data includes all data
98217fb1563SFerruh Yigit 	 * for all active touches.
98317fb1563SFerruh Yigit 	 * Event data also includes button data
98417fb1563SFerruh Yigit 	 */
98517fb1563SFerruh Yigit 	/*
98617fb1563SFerruh Yigit 	 * Use 2 reads:
98717fb1563SFerruh Yigit 	 * 1st read to get mode + button bytes + touch count (core)
98817fb1563SFerruh Yigit 	 * 2nd read (optional) to get touch 1 - touch n data
98917fb1563SFerruh Yigit 	 */
99017fb1563SFerruh Yigit 	hst_mode = si->xy_mode[CY_REG_BASE];
99117fb1563SFerruh Yigit 	rep_len = si->xy_mode[si->si_ofs.rep_ofs];
99217fb1563SFerruh Yigit 	rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1];
99317fb1563SFerruh Yigit 	tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs];
99417fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__,
99517fb1563SFerruh Yigit 		"hst_mode=", hst_mode, "rep_len=", rep_len,
99617fb1563SFerruh Yigit 		"rep_stat=", rep_stat, "tt_stat=", tt_stat);
99717fb1563SFerruh Yigit 
99817fb1563SFerruh Yigit 	num_cur_tch = GET_NUM_TOUCHES(tt_stat);
99917fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch);
100017fb1563SFerruh Yigit 
100117fb1563SFerruh Yigit 	if (rep_len == 0 && num_cur_tch > 0) {
100217fb1563SFerruh Yigit 		dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n",
100317fb1563SFerruh Yigit 			__func__, rep_len, num_cur_tch);
100417fb1563SFerruh Yigit 		goto cyttsp4_xy_worker_exit;
100517fb1563SFerruh Yigit 	}
100617fb1563SFerruh Yigit 
100717fb1563SFerruh Yigit 	/* read touches */
100817fb1563SFerruh Yigit 	if (num_cur_tch > 0) {
100917fb1563SFerruh Yigit 		rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1,
101017fb1563SFerruh Yigit 				num_cur_tch * si->si_ofs.tch_rec_size,
101117fb1563SFerruh Yigit 				si->xy_data);
101217fb1563SFerruh Yigit 		if (rc < 0) {
101317fb1563SFerruh Yigit 			dev_err(dev, "%s: read fail on touch regs r=%d\n",
101417fb1563SFerruh Yigit 				__func__, rc);
101517fb1563SFerruh Yigit 			goto cyttsp4_xy_worker_exit;
101617fb1563SFerruh Yigit 		}
101717fb1563SFerruh Yigit 	}
101817fb1563SFerruh Yigit 
101917fb1563SFerruh Yigit 	/* print xy data */
102017fb1563SFerruh Yigit 	cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch *
102117fb1563SFerruh Yigit 		si->si_ofs.tch_rec_size, "xy_data");
102217fb1563SFerruh Yigit 
102317fb1563SFerruh Yigit 	/* check any error conditions */
102417fb1563SFerruh Yigit 	if (IS_BAD_PKT(rep_stat)) {
102517fb1563SFerruh Yigit 		dev_dbg(dev, "%s: Invalid buffer detected\n", __func__);
102617fb1563SFerruh Yigit 		rc = 0;
102717fb1563SFerruh Yigit 		goto cyttsp4_xy_worker_exit;
102817fb1563SFerruh Yigit 	}
102917fb1563SFerruh Yigit 
103017fb1563SFerruh Yigit 	if (IS_LARGE_AREA(tt_stat))
103117fb1563SFerruh Yigit 		dev_dbg(dev, "%s: Large area detected\n", __func__);
103217fb1563SFerruh Yigit 
103317fb1563SFerruh Yigit 	if (num_cur_tch > si->si_ofs.max_tchs) {
10345b5e0928SAlexey Dobriyan 		dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%zd)\n",
103517fb1563SFerruh Yigit 				__func__, num_cur_tch, si->si_ofs.max_tchs);
103617fb1563SFerruh Yigit 		num_cur_tch = si->si_ofs.max_tchs;
103717fb1563SFerruh Yigit 	}
103817fb1563SFerruh Yigit 
103917fb1563SFerruh Yigit 	/* extract xy_data for all currently reported touches */
104017fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
104117fb1563SFerruh Yigit 		num_cur_tch);
104217fb1563SFerruh Yigit 	if (num_cur_tch)
104317fb1563SFerruh Yigit 		cyttsp4_get_mt_touches(md, num_cur_tch);
104417fb1563SFerruh Yigit 	else
104517fb1563SFerruh Yigit 		cyttsp4_lift_all(md);
104617fb1563SFerruh Yigit 
104717fb1563SFerruh Yigit 	rc = 0;
104817fb1563SFerruh Yigit 
104917fb1563SFerruh Yigit cyttsp4_xy_worker_exit:
105017fb1563SFerruh Yigit 	return rc;
105117fb1563SFerruh Yigit }
105217fb1563SFerruh Yigit 
cyttsp4_mt_attention(struct cyttsp4 * cd)105317fb1563SFerruh Yigit static int cyttsp4_mt_attention(struct cyttsp4 *cd)
105417fb1563SFerruh Yigit {
105517fb1563SFerruh Yigit 	struct device *dev = cd->dev;
105617fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
105717fb1563SFerruh Yigit 	int rc = 0;
105817fb1563SFerruh Yigit 
105917fb1563SFerruh Yigit 	if (!md->si)
106017fb1563SFerruh Yigit 		return 0;
106117fb1563SFerruh Yigit 
106217fb1563SFerruh Yigit 	mutex_lock(&md->report_lock);
106317fb1563SFerruh Yigit 	if (!md->is_suspended) {
106417fb1563SFerruh Yigit 		/* core handles handshake */
106517fb1563SFerruh Yigit 		rc = cyttsp4_xy_worker(cd);
106617fb1563SFerruh Yigit 	} else {
106717fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Ignoring report while suspended\n",
106817fb1563SFerruh Yigit 			__func__);
106917fb1563SFerruh Yigit 	}
107017fb1563SFerruh Yigit 	mutex_unlock(&md->report_lock);
107117fb1563SFerruh Yigit 	if (rc < 0)
107217fb1563SFerruh Yigit 		dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
107317fb1563SFerruh Yigit 
107417fb1563SFerruh Yigit 	return rc;
107517fb1563SFerruh Yigit }
107617fb1563SFerruh Yigit 
cyttsp4_irq(int irq,void * handle)107717fb1563SFerruh Yigit static irqreturn_t cyttsp4_irq(int irq, void *handle)
107817fb1563SFerruh Yigit {
107917fb1563SFerruh Yigit 	struct cyttsp4 *cd = handle;
108017fb1563SFerruh Yigit 	struct device *dev = cd->dev;
108117fb1563SFerruh Yigit 	enum cyttsp4_mode cur_mode;
108217fb1563SFerruh Yigit 	u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs;
108317fb1563SFerruh Yigit 	u8 mode[3];
108417fb1563SFerruh Yigit 	int rc;
108517fb1563SFerruh Yigit 
108617fb1563SFerruh Yigit 	/*
108717fb1563SFerruh Yigit 	 * Check whether this IRQ should be ignored (external)
108817fb1563SFerruh Yigit 	 * This should be the very first thing to check since
108917fb1563SFerruh Yigit 	 * ignore_irq may be set for a very short period of time
109017fb1563SFerruh Yigit 	 */
109117fb1563SFerruh Yigit 	if (atomic_read(&cd->ignore_irq)) {
109217fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
109317fb1563SFerruh Yigit 		return IRQ_HANDLED;
109417fb1563SFerruh Yigit 	}
109517fb1563SFerruh Yigit 
109617fb1563SFerruh Yigit 	dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status);
109717fb1563SFerruh Yigit 
109817fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
109917fb1563SFerruh Yigit 
110017fb1563SFerruh Yigit 	/* Just to debug */
110117fb1563SFerruh Yigit 	if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING)
110217fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__);
110317fb1563SFerruh Yigit 
110417fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode);
110517fb1563SFerruh Yigit 	if (rc) {
110617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
110717fb1563SFerruh Yigit 		goto cyttsp4_irq_exit;
110817fb1563SFerruh Yigit 	}
110917fb1563SFerruh Yigit 	dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__,
111017fb1563SFerruh Yigit 			mode[0], mode[1], mode[2]);
111117fb1563SFerruh Yigit 
111217fb1563SFerruh Yigit 	if (IS_BOOTLOADER(mode[0], mode[1])) {
111317fb1563SFerruh Yigit 		cur_mode = CY_MODE_BOOTLOADER;
111417fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: bl running\n", __func__);
111517fb1563SFerruh Yigit 		if (cd->mode == CY_MODE_BOOTLOADER) {
111617fb1563SFerruh Yigit 			/* Signal bootloader heartbeat heard */
111717fb1563SFerruh Yigit 			wake_up(&cd->wait_q);
111817fb1563SFerruh Yigit 			goto cyttsp4_irq_exit;
111917fb1563SFerruh Yigit 		}
112017fb1563SFerruh Yigit 
112117fb1563SFerruh Yigit 		/* switch to bootloader */
112217fb1563SFerruh Yigit 		dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n",
112317fb1563SFerruh Yigit 			__func__, cd->mode, cur_mode);
112417fb1563SFerruh Yigit 
112517fb1563SFerruh Yigit 		/* catch operation->bl glitch */
112617fb1563SFerruh Yigit 		if (cd->mode != CY_MODE_UNKNOWN) {
112717fb1563SFerruh Yigit 			/* Incase startup_state do not let startup_() */
112817fb1563SFerruh Yigit 			cd->mode = CY_MODE_UNKNOWN;
112917fb1563SFerruh Yigit 			cyttsp4_queue_startup_(cd);
113017fb1563SFerruh Yigit 			goto cyttsp4_irq_exit;
113117fb1563SFerruh Yigit 		}
113217fb1563SFerruh Yigit 
113317fb1563SFerruh Yigit 		/*
113417fb1563SFerruh Yigit 		 * do not wake thread on this switch since
113517fb1563SFerruh Yigit 		 * it is possible to get an early heartbeat
113617fb1563SFerruh Yigit 		 * prior to performing the reset
113717fb1563SFerruh Yigit 		 */
113817fb1563SFerruh Yigit 		cd->mode = cur_mode;
113917fb1563SFerruh Yigit 
114017fb1563SFerruh Yigit 		goto cyttsp4_irq_exit;
114117fb1563SFerruh Yigit 	}
114217fb1563SFerruh Yigit 
114317fb1563SFerruh Yigit 	switch (mode[0] & CY_HST_MODE) {
114417fb1563SFerruh Yigit 	case CY_HST_OPERATE:
114517fb1563SFerruh Yigit 		cur_mode = CY_MODE_OPERATIONAL;
114617fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: operational\n", __func__);
114717fb1563SFerruh Yigit 		break;
114817fb1563SFerruh Yigit 	case CY_HST_CAT:
114917fb1563SFerruh Yigit 		cur_mode = CY_MODE_CAT;
115017fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: CaT\n", __func__);
115117fb1563SFerruh Yigit 		break;
115217fb1563SFerruh Yigit 	case CY_HST_SYSINFO:
115317fb1563SFerruh Yigit 		cur_mode = CY_MODE_SYSINFO;
115417fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: sysinfo\n", __func__);
115517fb1563SFerruh Yigit 		break;
115617fb1563SFerruh Yigit 	default:
115717fb1563SFerruh Yigit 		cur_mode = CY_MODE_UNKNOWN;
115817fb1563SFerruh Yigit 		dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__,
115917fb1563SFerruh Yigit 			mode[0]);
116017fb1563SFerruh Yigit 		break;
116117fb1563SFerruh Yigit 	}
116217fb1563SFerruh Yigit 
116317fb1563SFerruh Yigit 	/* Check whether this IRQ should be ignored (internal) */
116417fb1563SFerruh Yigit 	if (cd->int_status & CY_INT_IGNORE) {
116517fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
116617fb1563SFerruh Yigit 		goto cyttsp4_irq_exit;
116717fb1563SFerruh Yigit 	}
116817fb1563SFerruh Yigit 
116917fb1563SFerruh Yigit 	/* Check for wake up interrupt */
117017fb1563SFerruh Yigit 	if (cd->int_status & CY_INT_AWAKE) {
117117fb1563SFerruh Yigit 		cd->int_status &= ~CY_INT_AWAKE;
117217fb1563SFerruh Yigit 		wake_up(&cd->wait_q);
117317fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__);
117417fb1563SFerruh Yigit 		goto cyttsp4_irq_handshake;
117517fb1563SFerruh Yigit 	}
117617fb1563SFerruh Yigit 
117717fb1563SFerruh Yigit 	/* Expecting mode change interrupt */
117817fb1563SFerruh Yigit 	if ((cd->int_status & CY_INT_MODE_CHANGE)
117917fb1563SFerruh Yigit 			&& (mode[0] & CY_HST_MODE_CHANGE) == 0) {
118017fb1563SFerruh Yigit 		cd->int_status &= ~CY_INT_MODE_CHANGE;
118117fb1563SFerruh Yigit 		dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n",
118217fb1563SFerruh Yigit 				__func__, cd->mode, cur_mode);
118317fb1563SFerruh Yigit 		cd->mode = cur_mode;
118417fb1563SFerruh Yigit 		wake_up(&cd->wait_q);
118517fb1563SFerruh Yigit 		goto cyttsp4_irq_handshake;
118617fb1563SFerruh Yigit 	}
118717fb1563SFerruh Yigit 
118817fb1563SFerruh Yigit 	/* compare current core mode to current device mode */
118917fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n",
119017fb1563SFerruh Yigit 			__func__, cd->mode, cur_mode);
119117fb1563SFerruh Yigit 	if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) {
119217fb1563SFerruh Yigit 		/* Unexpected mode change occurred */
119317fb1563SFerruh Yigit 		dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode,
119417fb1563SFerruh Yigit 				cur_mode, cd->int_status);
119517fb1563SFerruh Yigit 		dev_dbg(dev, "%s: Unexpected mode change, startup\n",
119617fb1563SFerruh Yigit 				__func__);
119717fb1563SFerruh Yigit 		cyttsp4_queue_startup_(cd);
119817fb1563SFerruh Yigit 		goto cyttsp4_irq_exit;
119917fb1563SFerruh Yigit 	}
120017fb1563SFerruh Yigit 
120117fb1563SFerruh Yigit 	/* Expecting command complete interrupt */
120217fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]);
120317fb1563SFerruh Yigit 	if ((cd->int_status & CY_INT_EXEC_CMD)
120417fb1563SFerruh Yigit 			&& mode[cmd_ofs] & CY_CMD_COMPLETE) {
120517fb1563SFerruh Yigit 		cd->int_status &= ~CY_INT_EXEC_CMD;
120617fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Received command complete interrupt\n",
120717fb1563SFerruh Yigit 				__func__);
120817fb1563SFerruh Yigit 		wake_up(&cd->wait_q);
120917fb1563SFerruh Yigit 		/*
121017fb1563SFerruh Yigit 		 * It is possible to receive a single interrupt for
121117fb1563SFerruh Yigit 		 * command complete and touch/button status report.
121217fb1563SFerruh Yigit 		 * Continue processing for a possible status report.
121317fb1563SFerruh Yigit 		 */
121417fb1563SFerruh Yigit 	}
121517fb1563SFerruh Yigit 
121617fb1563SFerruh Yigit 	/* This should be status report, read status regs */
121717fb1563SFerruh Yigit 	if (cd->mode == CY_MODE_OPERATIONAL) {
121817fb1563SFerruh Yigit 		dev_vdbg(dev, "%s: Read status registers\n", __func__);
121917fb1563SFerruh Yigit 		rc = cyttsp4_load_status_regs(cd);
122017fb1563SFerruh Yigit 		if (rc < 0)
122117fb1563SFerruh Yigit 			dev_err(dev, "%s: fail read mode regs r=%d\n",
122217fb1563SFerruh Yigit 				__func__, rc);
122317fb1563SFerruh Yigit 	}
122417fb1563SFerruh Yigit 
122517fb1563SFerruh Yigit 	cyttsp4_mt_attention(cd);
122617fb1563SFerruh Yigit 
122717fb1563SFerruh Yigit cyttsp4_irq_handshake:
122817fb1563SFerruh Yigit 	/* handshake the event */
122917fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n",
123017fb1563SFerruh Yigit 			__func__, mode[0], rc);
123117fb1563SFerruh Yigit 	rc = cyttsp4_handshake(cd, mode[0]);
123217fb1563SFerruh Yigit 	if (rc < 0)
123317fb1563SFerruh Yigit 		dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n",
123417fb1563SFerruh Yigit 				__func__, mode[0], rc);
123517fb1563SFerruh Yigit 
123617fb1563SFerruh Yigit 	/*
123717fb1563SFerruh Yigit 	 * a non-zero udelay period is required for using
123817fb1563SFerruh Yigit 	 * IRQF_TRIGGER_LOW in order to delay until the
123917fb1563SFerruh Yigit 	 * device completes isr deassert
124017fb1563SFerruh Yigit 	 */
124117fb1563SFerruh Yigit 	udelay(cd->cpdata->level_irq_udelay);
124217fb1563SFerruh Yigit 
124317fb1563SFerruh Yigit cyttsp4_irq_exit:
124417fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
124517fb1563SFerruh Yigit 	return IRQ_HANDLED;
124617fb1563SFerruh Yigit }
124717fb1563SFerruh Yigit 
cyttsp4_start_wd_timer(struct cyttsp4 * cd)124817fb1563SFerruh Yigit static void cyttsp4_start_wd_timer(struct cyttsp4 *cd)
124917fb1563SFerruh Yigit {
125017fb1563SFerruh Yigit 	if (!CY_WATCHDOG_TIMEOUT)
125117fb1563SFerruh Yigit 		return;
125217fb1563SFerruh Yigit 
125317fb1563SFerruh Yigit 	mod_timer(&cd->watchdog_timer, jiffies +
125417fb1563SFerruh Yigit 			msecs_to_jiffies(CY_WATCHDOG_TIMEOUT));
125517fb1563SFerruh Yigit }
125617fb1563SFerruh Yigit 
cyttsp4_stop_wd_timer(struct cyttsp4 * cd)125717fb1563SFerruh Yigit static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
125817fb1563SFerruh Yigit {
125917fb1563SFerruh Yigit 	if (!CY_WATCHDOG_TIMEOUT)
126017fb1563SFerruh Yigit 		return;
126117fb1563SFerruh Yigit 
126217fb1563SFerruh Yigit 	/*
126317fb1563SFerruh Yigit 	 * Ensure we wait until the watchdog timer
126417fb1563SFerruh Yigit 	 * running on a different CPU finishes
126517fb1563SFerruh Yigit 	 */
1266*dbe83657SDuoming Zhou 	timer_shutdown_sync(&cd->watchdog_timer);
126717fb1563SFerruh Yigit 	cancel_work_sync(&cd->watchdog_work);
126817fb1563SFerruh Yigit }
126917fb1563SFerruh Yigit 
cyttsp4_watchdog_timer(struct timer_list * t)1270ee03e3f0SKees Cook static void cyttsp4_watchdog_timer(struct timer_list *t)
127117fb1563SFerruh Yigit {
1272ee03e3f0SKees Cook 	struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
127317fb1563SFerruh Yigit 
127417fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
127517fb1563SFerruh Yigit 
127617fb1563SFerruh Yigit 	schedule_work(&cd->watchdog_work);
127717fb1563SFerruh Yigit 
127817fb1563SFerruh Yigit 	return;
127917fb1563SFerruh Yigit }
128017fb1563SFerruh Yigit 
cyttsp4_request_exclusive(struct cyttsp4 * cd,void * ownptr,int timeout_ms)128117fb1563SFerruh Yigit static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr,
128217fb1563SFerruh Yigit 		int timeout_ms)
128317fb1563SFerruh Yigit {
128417fb1563SFerruh Yigit 	int t = msecs_to_jiffies(timeout_ms);
128517fb1563SFerruh Yigit 	bool with_timeout = (timeout_ms != 0);
128617fb1563SFerruh Yigit 
128717fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
128817fb1563SFerruh Yigit 	if (!cd->exclusive_dev && cd->exclusive_waits == 0) {
128917fb1563SFerruh Yigit 		cd->exclusive_dev = ownptr;
129017fb1563SFerruh Yigit 		goto exit;
129117fb1563SFerruh Yigit 	}
129217fb1563SFerruh Yigit 
129317fb1563SFerruh Yigit 	cd->exclusive_waits++;
129417fb1563SFerruh Yigit wait:
129517fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
129617fb1563SFerruh Yigit 	if (with_timeout) {
129717fb1563SFerruh Yigit 		t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t);
129817fb1563SFerruh Yigit 		if (IS_TMO(t)) {
129917fb1563SFerruh Yigit 			dev_err(cd->dev, "%s: tmo waiting exclusive access\n",
130017fb1563SFerruh Yigit 				__func__);
130117fb1563SFerruh Yigit 			mutex_lock(&cd->system_lock);
130217fb1563SFerruh Yigit 			cd->exclusive_waits--;
130317fb1563SFerruh Yigit 			mutex_unlock(&cd->system_lock);
130417fb1563SFerruh Yigit 			return -ETIME;
130517fb1563SFerruh Yigit 		}
130617fb1563SFerruh Yigit 	} else {
130717fb1563SFerruh Yigit 		wait_event(cd->wait_q, !cd->exclusive_dev);
130817fb1563SFerruh Yigit 	}
130917fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
131017fb1563SFerruh Yigit 	if (cd->exclusive_dev)
131117fb1563SFerruh Yigit 		goto wait;
131217fb1563SFerruh Yigit 	cd->exclusive_dev = ownptr;
131317fb1563SFerruh Yigit 	cd->exclusive_waits--;
131417fb1563SFerruh Yigit exit:
131517fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
131617fb1563SFerruh Yigit 
131717fb1563SFerruh Yigit 	return 0;
131817fb1563SFerruh Yigit }
131917fb1563SFerruh Yigit 
132017fb1563SFerruh Yigit /*
132117fb1563SFerruh Yigit  * returns error if was not owned
132217fb1563SFerruh Yigit  */
cyttsp4_release_exclusive(struct cyttsp4 * cd,void * ownptr)132317fb1563SFerruh Yigit static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr)
132417fb1563SFerruh Yigit {
132517fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
132617fb1563SFerruh Yigit 	if (cd->exclusive_dev != ownptr) {
132717fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
132817fb1563SFerruh Yigit 		return -EINVAL;
132917fb1563SFerruh Yigit 	}
133017fb1563SFerruh Yigit 
133117fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n",
133217fb1563SFerruh Yigit 		__func__, cd->exclusive_dev);
133317fb1563SFerruh Yigit 	cd->exclusive_dev = NULL;
133417fb1563SFerruh Yigit 	wake_up(&cd->wait_q);
133517fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
133617fb1563SFerruh Yigit 	return 0;
133717fb1563SFerruh Yigit }
133817fb1563SFerruh Yigit 
cyttsp4_wait_bl_heartbeat(struct cyttsp4 * cd)133917fb1563SFerruh Yigit static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd)
134017fb1563SFerruh Yigit {
134117fb1563SFerruh Yigit 	long t;
134217fb1563SFerruh Yigit 	int rc = 0;
134317fb1563SFerruh Yigit 
134417fb1563SFerruh Yigit 	/* wait heartbeat */
134517fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__);
134617fb1563SFerruh Yigit 	t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER,
134717fb1563SFerruh Yigit 			msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT));
134817fb1563SFerruh Yigit 	if (IS_TMO(t)) {
134917fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n",
135017fb1563SFerruh Yigit 			__func__, cd->mode);
135117fb1563SFerruh Yigit 		rc = -ETIME;
135217fb1563SFerruh Yigit 	}
135317fb1563SFerruh Yigit 
135417fb1563SFerruh Yigit 	return rc;
135517fb1563SFerruh Yigit }
135617fb1563SFerruh Yigit 
cyttsp4_wait_sysinfo_mode(struct cyttsp4 * cd)135717fb1563SFerruh Yigit static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd)
135817fb1563SFerruh Yigit {
135917fb1563SFerruh Yigit 	long t;
136017fb1563SFerruh Yigit 
136117fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__);
136217fb1563SFerruh Yigit 
136317fb1563SFerruh Yigit 	t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO,
136417fb1563SFerruh Yigit 			msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
136517fb1563SFerruh Yigit 	if (IS_TMO(t)) {
136617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n",
136717fb1563SFerruh Yigit 			__func__, cd->mode);
136817fb1563SFerruh Yigit 		mutex_lock(&cd->system_lock);
136917fb1563SFerruh Yigit 		cd->int_status &= ~CY_INT_MODE_CHANGE;
137017fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
137117fb1563SFerruh Yigit 		return -ETIME;
137217fb1563SFerruh Yigit 	}
137317fb1563SFerruh Yigit 
137417fb1563SFerruh Yigit 	return 0;
137517fb1563SFerruh Yigit }
137617fb1563SFerruh Yigit 
cyttsp4_reset_and_wait(struct cyttsp4 * cd)137717fb1563SFerruh Yigit static int cyttsp4_reset_and_wait(struct cyttsp4 *cd)
137817fb1563SFerruh Yigit {
137917fb1563SFerruh Yigit 	int rc;
138017fb1563SFerruh Yigit 
138117fb1563SFerruh Yigit 	/* reset hardware */
138217fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
138317fb1563SFerruh Yigit 	dev_dbg(cd->dev, "%s: reset hw...\n", __func__);
138417fb1563SFerruh Yigit 	rc = cyttsp4_hw_reset(cd);
138517fb1563SFerruh Yigit 	cd->mode = CY_MODE_UNKNOWN;
138617fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
138717fb1563SFerruh Yigit 	if (rc < 0) {
138817fb1563SFerruh Yigit 		dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc);
138917fb1563SFerruh Yigit 		return rc;
139017fb1563SFerruh Yigit 	}
139117fb1563SFerruh Yigit 
139217fb1563SFerruh Yigit 	return cyttsp4_wait_bl_heartbeat(cd);
139317fb1563SFerruh Yigit }
139417fb1563SFerruh Yigit 
139517fb1563SFerruh Yigit /*
139617fb1563SFerruh Yigit  * returns err if refused or timeout; block until mode change complete
139717fb1563SFerruh Yigit  * bit is set (mode change interrupt)
139817fb1563SFerruh Yigit  */
cyttsp4_set_mode(struct cyttsp4 * cd,int new_mode)139917fb1563SFerruh Yigit static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode)
140017fb1563SFerruh Yigit {
140117fb1563SFerruh Yigit 	u8 new_dev_mode;
140217fb1563SFerruh Yigit 	u8 mode;
140317fb1563SFerruh Yigit 	long t;
140417fb1563SFerruh Yigit 	int rc;
140517fb1563SFerruh Yigit 
140617fb1563SFerruh Yigit 	switch (new_mode) {
140717fb1563SFerruh Yigit 	case CY_MODE_OPERATIONAL:
140817fb1563SFerruh Yigit 		new_dev_mode = CY_HST_OPERATE;
140917fb1563SFerruh Yigit 		break;
141017fb1563SFerruh Yigit 	case CY_MODE_SYSINFO:
141117fb1563SFerruh Yigit 		new_dev_mode = CY_HST_SYSINFO;
141217fb1563SFerruh Yigit 		break;
141317fb1563SFerruh Yigit 	case CY_MODE_CAT:
141417fb1563SFerruh Yigit 		new_dev_mode = CY_HST_CAT;
141517fb1563SFerruh Yigit 		break;
141617fb1563SFerruh Yigit 	default:
141717fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n",
141817fb1563SFerruh Yigit 			__func__, new_mode, new_mode);
141917fb1563SFerruh Yigit 		return -EINVAL;
142017fb1563SFerruh Yigit 	}
142117fb1563SFerruh Yigit 
142217fb1563SFerruh Yigit 	/* change mode */
142317fb1563SFerruh Yigit 	dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n",
142417fb1563SFerruh Yigit 			__func__, "have exclusive", cd->exclusive_dev,
142517fb1563SFerruh Yigit 			new_dev_mode, new_mode);
142617fb1563SFerruh Yigit 
142717fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
142817fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
142917fb1563SFerruh Yigit 	if (rc < 0) {
143017fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
143117fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail read mode r=%d\n",
143217fb1563SFerruh Yigit 			__func__, rc);
143317fb1563SFerruh Yigit 		goto exit;
143417fb1563SFerruh Yigit 	}
143517fb1563SFerruh Yigit 
143617fb1563SFerruh Yigit 	/* Clear device mode bits and set to new mode */
143717fb1563SFerruh Yigit 	mode &= ~CY_HST_MODE;
143817fb1563SFerruh Yigit 	mode |= new_dev_mode | CY_HST_MODE_CHANGE;
143917fb1563SFerruh Yigit 
144017fb1563SFerruh Yigit 	cd->int_status |= CY_INT_MODE_CHANGE;
144117fb1563SFerruh Yigit 	rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode);
144217fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
144317fb1563SFerruh Yigit 	if (rc < 0) {
144417fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail write mode change r=%d\n",
144517fb1563SFerruh Yigit 				__func__, rc);
144617fb1563SFerruh Yigit 		goto exit;
144717fb1563SFerruh Yigit 	}
144817fb1563SFerruh Yigit 
144917fb1563SFerruh Yigit 	/* wait for mode change done interrupt */
145017fb1563SFerruh Yigit 	t = wait_event_timeout(cd->wait_q,
145117fb1563SFerruh Yigit 			(cd->int_status & CY_INT_MODE_CHANGE) == 0,
145217fb1563SFerruh Yigit 			msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
145317fb1563SFerruh Yigit 	dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n",
145417fb1563SFerruh Yigit 			__func__, t, cd->mode);
145517fb1563SFerruh Yigit 
145617fb1563SFerruh Yigit 	if (IS_TMO(t)) {
145717fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: %s\n", __func__,
145817fb1563SFerruh Yigit 				"tmo waiting mode change");
145917fb1563SFerruh Yigit 		mutex_lock(&cd->system_lock);
146017fb1563SFerruh Yigit 		cd->int_status &= ~CY_INT_MODE_CHANGE;
146117fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
146217fb1563SFerruh Yigit 		rc = -EINVAL;
146317fb1563SFerruh Yigit 	}
146417fb1563SFerruh Yigit 
146517fb1563SFerruh Yigit exit:
146617fb1563SFerruh Yigit 	return rc;
146717fb1563SFerruh Yigit }
146817fb1563SFerruh Yigit 
cyttsp4_watchdog_work(struct work_struct * work)146917fb1563SFerruh Yigit static void cyttsp4_watchdog_work(struct work_struct *work)
147017fb1563SFerruh Yigit {
147117fb1563SFerruh Yigit 	struct cyttsp4 *cd =
147217fb1563SFerruh Yigit 		container_of(work, struct cyttsp4, watchdog_work);
147317fb1563SFerruh Yigit 	u8 *mode;
147417fb1563SFerruh Yigit 	int retval;
147517fb1563SFerruh Yigit 
147617fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
147717fb1563SFerruh Yigit 	retval = cyttsp4_load_status_regs(cd);
147817fb1563SFerruh Yigit 	if (retval < 0) {
147917fb1563SFerruh Yigit 		dev_err(cd->dev,
148017fb1563SFerruh Yigit 			"%s: failed to access device in watchdog timer r=%d\n",
148117fb1563SFerruh Yigit 			__func__, retval);
148217fb1563SFerruh Yigit 		cyttsp4_queue_startup_(cd);
148317fb1563SFerruh Yigit 		goto cyttsp4_timer_watchdog_exit_error;
148417fb1563SFerruh Yigit 	}
148517fb1563SFerruh Yigit 	mode = &cd->sysinfo.xy_mode[CY_REG_BASE];
148617fb1563SFerruh Yigit 	if (IS_BOOTLOADER(mode[0], mode[1])) {
148717fb1563SFerruh Yigit 		dev_err(cd->dev,
148817fb1563SFerruh Yigit 			"%s: device found in bootloader mode when operational mode\n",
148917fb1563SFerruh Yigit 			__func__);
149017fb1563SFerruh Yigit 		cyttsp4_queue_startup_(cd);
149117fb1563SFerruh Yigit 		goto cyttsp4_timer_watchdog_exit_error;
149217fb1563SFerruh Yigit 	}
149317fb1563SFerruh Yigit 
149417fb1563SFerruh Yigit 	cyttsp4_start_wd_timer(cd);
149517fb1563SFerruh Yigit cyttsp4_timer_watchdog_exit_error:
149617fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
149717fb1563SFerruh Yigit 	return;
149817fb1563SFerruh Yigit }
149917fb1563SFerruh Yigit 
cyttsp4_core_sleep_(struct cyttsp4 * cd)150017fb1563SFerruh Yigit static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
150117fb1563SFerruh Yigit {
150217fb1563SFerruh Yigit 	enum cyttsp4_sleep_state ss = SS_SLEEP_ON;
150317fb1563SFerruh Yigit 	enum cyttsp4_int_state int_status = CY_INT_IGNORE;
150417fb1563SFerruh Yigit 	int rc = 0;
150517fb1563SFerruh Yigit 	u8 mode[2];
150617fb1563SFerruh Yigit 
150717fb1563SFerruh Yigit 	/* Already in sleep mode? */
150817fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
150917fb1563SFerruh Yigit 	if (cd->sleep_state == SS_SLEEP_ON) {
151017fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
151117fb1563SFerruh Yigit 		return 0;
151217fb1563SFerruh Yigit 	}
151317fb1563SFerruh Yigit 	cd->sleep_state = SS_SLEEPING;
151417fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
151517fb1563SFerruh Yigit 
151617fb1563SFerruh Yigit 	cyttsp4_stop_wd_timer(cd);
151717fb1563SFerruh Yigit 
151817fb1563SFerruh Yigit 	/* Wait until currently running IRQ handler exits and disable IRQ */
151917fb1563SFerruh Yigit 	disable_irq(cd->irq);
152017fb1563SFerruh Yigit 
152117fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__);
152217fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
152317fb1563SFerruh Yigit 	rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
152417fb1563SFerruh Yigit 	if (rc) {
152517fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
152617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
152717fb1563SFerruh Yigit 		goto error;
152817fb1563SFerruh Yigit 	}
152917fb1563SFerruh Yigit 
153017fb1563SFerruh Yigit 	if (IS_BOOTLOADER(mode[0], mode[1])) {
153117fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
1532c01e0159SMasanari Iida 		dev_err(cd->dev, "%s: Device in BOOTLOADER mode.\n", __func__);
153317fb1563SFerruh Yigit 		rc = -EINVAL;
153417fb1563SFerruh Yigit 		goto error;
153517fb1563SFerruh Yigit 	}
153617fb1563SFerruh Yigit 
153717fb1563SFerruh Yigit 	mode[0] |= CY_HST_SLEEP;
153817fb1563SFerruh Yigit 	rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]);
153917fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
154017fb1563SFerruh Yigit 	if (rc) {
154117fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc);
154217fb1563SFerruh Yigit 		goto error;
154317fb1563SFerruh Yigit 	}
154417fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__);
154517fb1563SFerruh Yigit 
154617fb1563SFerruh Yigit 	if (cd->cpdata->power) {
154717fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: Power down HW\n", __func__);
154817fb1563SFerruh Yigit 		rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq);
154917fb1563SFerruh Yigit 	} else {
155017fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: No power function\n", __func__);
155117fb1563SFerruh Yigit 		rc = 0;
155217fb1563SFerruh Yigit 	}
155317fb1563SFerruh Yigit 	if (rc < 0) {
155417fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: HW Power down fails r=%d\n",
155517fb1563SFerruh Yigit 				__func__, rc);
155617fb1563SFerruh Yigit 		goto error;
155717fb1563SFerruh Yigit 	}
155817fb1563SFerruh Yigit 
155917fb1563SFerruh Yigit 	/* Give time to FW to sleep */
156017fb1563SFerruh Yigit 	msleep(50);
156117fb1563SFerruh Yigit 
156217fb1563SFerruh Yigit 	goto exit;
156317fb1563SFerruh Yigit 
156417fb1563SFerruh Yigit error:
156517fb1563SFerruh Yigit 	ss = SS_SLEEP_OFF;
156617fb1563SFerruh Yigit 	int_status = CY_INT_NONE;
156717fb1563SFerruh Yigit 	cyttsp4_start_wd_timer(cd);
156817fb1563SFerruh Yigit 
156917fb1563SFerruh Yigit exit:
157017fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
157117fb1563SFerruh Yigit 	cd->sleep_state = ss;
157217fb1563SFerruh Yigit 	cd->int_status |= int_status;
157317fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
157417fb1563SFerruh Yigit 	enable_irq(cd->irq);
157517fb1563SFerruh Yigit 	return rc;
157617fb1563SFerruh Yigit }
157717fb1563SFerruh Yigit 
cyttsp4_startup_(struct cyttsp4 * cd)157817fb1563SFerruh Yigit static int cyttsp4_startup_(struct cyttsp4 *cd)
157917fb1563SFerruh Yigit {
158017fb1563SFerruh Yigit 	int retry = CY_CORE_STARTUP_RETRY_COUNT;
158117fb1563SFerruh Yigit 	int rc;
158217fb1563SFerruh Yigit 
158317fb1563SFerruh Yigit 	cyttsp4_stop_wd_timer(cd);
158417fb1563SFerruh Yigit 
158517fb1563SFerruh Yigit reset:
158617fb1563SFerruh Yigit 	if (retry != CY_CORE_STARTUP_RETRY_COUNT)
158717fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: Retry %d\n", __func__,
158817fb1563SFerruh Yigit 			CY_CORE_STARTUP_RETRY_COUNT - retry);
158917fb1563SFerruh Yigit 
159017fb1563SFerruh Yigit 	/* reset hardware and wait for heartbeat */
159117fb1563SFerruh Yigit 	rc = cyttsp4_reset_and_wait(cd);
159217fb1563SFerruh Yigit 	if (rc < 0) {
159317fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc);
159417fb1563SFerruh Yigit 		if (retry--)
159517fb1563SFerruh Yigit 			goto reset;
159617fb1563SFerruh Yigit 		goto exit;
159717fb1563SFerruh Yigit 	}
159817fb1563SFerruh Yigit 
159917fb1563SFerruh Yigit 	/* exit bl into sysinfo mode */
160017fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__);
160117fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
160217fb1563SFerruh Yigit 	cd->int_status &= ~CY_INT_IGNORE;
160317fb1563SFerruh Yigit 	cd->int_status |= CY_INT_MODE_CHANGE;
160417fb1563SFerruh Yigit 
160517fb1563SFerruh Yigit 	rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit),
160617fb1563SFerruh Yigit 			(u8 *)ldr_exit);
160717fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
160817fb1563SFerruh Yigit 	if (rc < 0) {
160917fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc);
161017fb1563SFerruh Yigit 		if (retry--)
161117fb1563SFerruh Yigit 			goto reset;
161217fb1563SFerruh Yigit 		goto exit;
161317fb1563SFerruh Yigit 	}
161417fb1563SFerruh Yigit 
161517fb1563SFerruh Yigit 	rc = cyttsp4_wait_sysinfo_mode(cd);
161617fb1563SFerruh Yigit 	if (rc < 0) {
161717fb1563SFerruh Yigit 		u8 buf[sizeof(ldr_err_app)];
161817fb1563SFerruh Yigit 		int rc1;
161917fb1563SFerruh Yigit 
162017fb1563SFerruh Yigit 		/* Check for invalid/corrupted touch application */
162117fb1563SFerruh Yigit 		rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app),
162217fb1563SFerruh Yigit 				buf);
162317fb1563SFerruh Yigit 		if (rc1) {
162417fb1563SFerruh Yigit 			dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1);
162517fb1563SFerruh Yigit 		} else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) {
162617fb1563SFerruh Yigit 			dev_err(cd->dev, "%s: Error launching touch application\n",
162717fb1563SFerruh Yigit 				__func__);
162817fb1563SFerruh Yigit 			mutex_lock(&cd->system_lock);
162917fb1563SFerruh Yigit 			cd->invalid_touch_app = true;
163017fb1563SFerruh Yigit 			mutex_unlock(&cd->system_lock);
163117fb1563SFerruh Yigit 			goto exit_no_wd;
163217fb1563SFerruh Yigit 		}
163317fb1563SFerruh Yigit 
163417fb1563SFerruh Yigit 		if (retry--)
163517fb1563SFerruh Yigit 			goto reset;
163617fb1563SFerruh Yigit 		goto exit;
163717fb1563SFerruh Yigit 	}
163817fb1563SFerruh Yigit 
163917fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
164017fb1563SFerruh Yigit 	cd->invalid_touch_app = false;
164117fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
164217fb1563SFerruh Yigit 
164317fb1563SFerruh Yigit 	/* read sysinfo data */
164417fb1563SFerruh Yigit 	dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__);
164517fb1563SFerruh Yigit 	rc = cyttsp4_get_sysinfo_regs(cd);
164617fb1563SFerruh Yigit 	if (rc < 0) {
164717fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n",
164817fb1563SFerruh Yigit 			__func__, rc);
164917fb1563SFerruh Yigit 		if (retry--)
165017fb1563SFerruh Yigit 			goto reset;
165117fb1563SFerruh Yigit 		goto exit;
165217fb1563SFerruh Yigit 	}
165317fb1563SFerruh Yigit 
165417fb1563SFerruh Yigit 	rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL);
165517fb1563SFerruh Yigit 	if (rc < 0) {
165617fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n",
165717fb1563SFerruh Yigit 			__func__, rc);
165817fb1563SFerruh Yigit 		if (retry--)
165917fb1563SFerruh Yigit 			goto reset;
166017fb1563SFerruh Yigit 		goto exit;
166117fb1563SFerruh Yigit 	}
166217fb1563SFerruh Yigit 
166317fb1563SFerruh Yigit 	cyttsp4_lift_all(&cd->md);
166417fb1563SFerruh Yigit 
166517fb1563SFerruh Yigit 	/* restore to sleep if was suspended */
166617fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
166717fb1563SFerruh Yigit 	if (cd->sleep_state == SS_SLEEP_ON) {
166817fb1563SFerruh Yigit 		cd->sleep_state = SS_SLEEP_OFF;
166917fb1563SFerruh Yigit 		mutex_unlock(&cd->system_lock);
167017fb1563SFerruh Yigit 		cyttsp4_core_sleep_(cd);
167117fb1563SFerruh Yigit 		goto exit_no_wd;
167217fb1563SFerruh Yigit 	}
167317fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
167417fb1563SFerruh Yigit 
167517fb1563SFerruh Yigit exit:
167617fb1563SFerruh Yigit 	cyttsp4_start_wd_timer(cd);
167717fb1563SFerruh Yigit exit_no_wd:
167817fb1563SFerruh Yigit 	return rc;
167917fb1563SFerruh Yigit }
168017fb1563SFerruh Yigit 
cyttsp4_startup(struct cyttsp4 * cd)168117fb1563SFerruh Yigit static int cyttsp4_startup(struct cyttsp4 *cd)
168217fb1563SFerruh Yigit {
168317fb1563SFerruh Yigit 	int rc;
168417fb1563SFerruh Yigit 
168517fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
168617fb1563SFerruh Yigit 	cd->startup_state = STARTUP_RUNNING;
168717fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
168817fb1563SFerruh Yigit 
168917fb1563SFerruh Yigit 	rc = cyttsp4_request_exclusive(cd, cd->dev,
169017fb1563SFerruh Yigit 			CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
169117fb1563SFerruh Yigit 	if (rc < 0) {
169217fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
169317fb1563SFerruh Yigit 				__func__, cd->exclusive_dev, cd->dev);
169417fb1563SFerruh Yigit 		goto exit;
169517fb1563SFerruh Yigit 	}
169617fb1563SFerruh Yigit 
169717fb1563SFerruh Yigit 	rc = cyttsp4_startup_(cd);
169817fb1563SFerruh Yigit 
169917fb1563SFerruh Yigit 	if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
170017fb1563SFerruh Yigit 		/* Don't return fail code, mode is already changed. */
170117fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
170217fb1563SFerruh Yigit 	else
170317fb1563SFerruh Yigit 		dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
170417fb1563SFerruh Yigit 
170517fb1563SFerruh Yigit exit:
170617fb1563SFerruh Yigit 	mutex_lock(&cd->system_lock);
170717fb1563SFerruh Yigit 	cd->startup_state = STARTUP_NONE;
170817fb1563SFerruh Yigit 	mutex_unlock(&cd->system_lock);
170917fb1563SFerruh Yigit 
171017fb1563SFerruh Yigit 	/* Wake the waiters for end of startup */
171117fb1563SFerruh Yigit 	wake_up(&cd->wait_q);
171217fb1563SFerruh Yigit 
171317fb1563SFerruh Yigit 	return rc;
171417fb1563SFerruh Yigit }
171517fb1563SFerruh Yigit 
cyttsp4_startup_work_function(struct work_struct * work)171617fb1563SFerruh Yigit static void cyttsp4_startup_work_function(struct work_struct *work)
171717fb1563SFerruh Yigit {
171817fb1563SFerruh Yigit 	struct cyttsp4 *cd =  container_of(work, struct cyttsp4, startup_work);
171917fb1563SFerruh Yigit 	int rc;
172017fb1563SFerruh Yigit 
172117fb1563SFerruh Yigit 	rc = cyttsp4_startup(cd);
172217fb1563SFerruh Yigit 	if (rc < 0)
172317fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail queued startup r=%d\n",
172417fb1563SFerruh Yigit 			__func__, rc);
172517fb1563SFerruh Yigit }
172617fb1563SFerruh Yigit 
cyttsp4_free_si_ptrs(struct cyttsp4 * cd)172717fb1563SFerruh Yigit static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
172817fb1563SFerruh Yigit {
172917fb1563SFerruh Yigit 	struct cyttsp4_sysinfo *si = &cd->sysinfo;
173017fb1563SFerruh Yigit 
173117fb1563SFerruh Yigit 	if (!si)
173217fb1563SFerruh Yigit 		return;
173317fb1563SFerruh Yigit 
173417fb1563SFerruh Yigit 	kfree(si->si_ptrs.cydata);
173517fb1563SFerruh Yigit 	kfree(si->si_ptrs.test);
173617fb1563SFerruh Yigit 	kfree(si->si_ptrs.pcfg);
173717fb1563SFerruh Yigit 	kfree(si->si_ptrs.opcfg);
173817fb1563SFerruh Yigit 	kfree(si->si_ptrs.ddata);
173917fb1563SFerruh Yigit 	kfree(si->si_ptrs.mdata);
174017fb1563SFerruh Yigit 	kfree(si->btn);
174117fb1563SFerruh Yigit 	kfree(si->xy_mode);
174217fb1563SFerruh Yigit 	kfree(si->xy_data);
174317fb1563SFerruh Yigit 	kfree(si->btn_rec_data);
174417fb1563SFerruh Yigit }
174517fb1563SFerruh Yigit 
cyttsp4_core_sleep(struct cyttsp4 * cd)1746ca0abe3dSGeert Uytterhoeven static int cyttsp4_core_sleep(struct cyttsp4 *cd)
1747ca0abe3dSGeert Uytterhoeven {
1748ca0abe3dSGeert Uytterhoeven 	int rc;
1749ca0abe3dSGeert Uytterhoeven 
1750ca0abe3dSGeert Uytterhoeven 	rc = cyttsp4_request_exclusive(cd, cd->dev,
1751ca0abe3dSGeert Uytterhoeven 			CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
1752ca0abe3dSGeert Uytterhoeven 	if (rc < 0) {
1753ca0abe3dSGeert Uytterhoeven 		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
1754ca0abe3dSGeert Uytterhoeven 				__func__, cd->exclusive_dev, cd->dev);
1755ca0abe3dSGeert Uytterhoeven 		return 0;
1756ca0abe3dSGeert Uytterhoeven 	}
1757ca0abe3dSGeert Uytterhoeven 
1758ca0abe3dSGeert Uytterhoeven 	rc = cyttsp4_core_sleep_(cd);
1759ca0abe3dSGeert Uytterhoeven 
1760ca0abe3dSGeert Uytterhoeven 	if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
1761ca0abe3dSGeert Uytterhoeven 		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
1762ca0abe3dSGeert Uytterhoeven 	else
1763ca0abe3dSGeert Uytterhoeven 		dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
1764ca0abe3dSGeert Uytterhoeven 
1765ca0abe3dSGeert Uytterhoeven 	return rc;
1766ca0abe3dSGeert Uytterhoeven }
1767ca0abe3dSGeert Uytterhoeven 
cyttsp4_core_wake_(struct cyttsp4 * cd)1768ca0abe3dSGeert Uytterhoeven static int cyttsp4_core_wake_(struct cyttsp4 *cd)
1769ca0abe3dSGeert Uytterhoeven {
1770ca0abe3dSGeert Uytterhoeven 	struct device *dev = cd->dev;
1771ca0abe3dSGeert Uytterhoeven 	int rc;
1772ca0abe3dSGeert Uytterhoeven 	u8 mode;
1773ca0abe3dSGeert Uytterhoeven 	int t;
1774ca0abe3dSGeert Uytterhoeven 
1775ca0abe3dSGeert Uytterhoeven 	/* Already woken? */
1776ca0abe3dSGeert Uytterhoeven 	mutex_lock(&cd->system_lock);
1777ca0abe3dSGeert Uytterhoeven 	if (cd->sleep_state == SS_SLEEP_OFF) {
1778ca0abe3dSGeert Uytterhoeven 		mutex_unlock(&cd->system_lock);
1779ca0abe3dSGeert Uytterhoeven 		return 0;
1780ca0abe3dSGeert Uytterhoeven 	}
1781ca0abe3dSGeert Uytterhoeven 	cd->int_status &= ~CY_INT_IGNORE;
1782ca0abe3dSGeert Uytterhoeven 	cd->int_status |= CY_INT_AWAKE;
1783ca0abe3dSGeert Uytterhoeven 	cd->sleep_state = SS_WAKING;
1784ca0abe3dSGeert Uytterhoeven 
1785ca0abe3dSGeert Uytterhoeven 	if (cd->cpdata->power) {
1786ca0abe3dSGeert Uytterhoeven 		dev_dbg(dev, "%s: Power up HW\n", __func__);
1787ca0abe3dSGeert Uytterhoeven 		rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
1788ca0abe3dSGeert Uytterhoeven 	} else {
1789ca0abe3dSGeert Uytterhoeven 		dev_dbg(dev, "%s: No power function\n", __func__);
1790ca0abe3dSGeert Uytterhoeven 		rc = -ENOSYS;
1791ca0abe3dSGeert Uytterhoeven 	}
1792ca0abe3dSGeert Uytterhoeven 	if (rc < 0) {
1793ca0abe3dSGeert Uytterhoeven 		dev_err(dev, "%s: HW Power up fails r=%d\n",
1794ca0abe3dSGeert Uytterhoeven 				__func__, rc);
1795ca0abe3dSGeert Uytterhoeven 
1796ca0abe3dSGeert Uytterhoeven 		/* Initiate a read transaction to wake up */
1797ca0abe3dSGeert Uytterhoeven 		cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
1798ca0abe3dSGeert Uytterhoeven 	} else
1799ca0abe3dSGeert Uytterhoeven 		dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
1800ca0abe3dSGeert Uytterhoeven 			__func__);
1801ca0abe3dSGeert Uytterhoeven 	mutex_unlock(&cd->system_lock);
1802ca0abe3dSGeert Uytterhoeven 
1803ca0abe3dSGeert Uytterhoeven 	t = wait_event_timeout(cd->wait_q,
1804ca0abe3dSGeert Uytterhoeven 			(cd->int_status & CY_INT_AWAKE) == 0,
1805ca0abe3dSGeert Uytterhoeven 			msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
1806ca0abe3dSGeert Uytterhoeven 	if (IS_TMO(t)) {
1807ca0abe3dSGeert Uytterhoeven 		dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
1808ca0abe3dSGeert Uytterhoeven 		mutex_lock(&cd->system_lock);
1809ca0abe3dSGeert Uytterhoeven 		cd->int_status &= ~CY_INT_AWAKE;
1810ca0abe3dSGeert Uytterhoeven 		/* Try starting up */
1811ca0abe3dSGeert Uytterhoeven 		cyttsp4_queue_startup_(cd);
1812ca0abe3dSGeert Uytterhoeven 		mutex_unlock(&cd->system_lock);
1813ca0abe3dSGeert Uytterhoeven 	}
1814ca0abe3dSGeert Uytterhoeven 
1815ca0abe3dSGeert Uytterhoeven 	mutex_lock(&cd->system_lock);
1816ca0abe3dSGeert Uytterhoeven 	cd->sleep_state = SS_SLEEP_OFF;
1817ca0abe3dSGeert Uytterhoeven 	mutex_unlock(&cd->system_lock);
1818ca0abe3dSGeert Uytterhoeven 
1819ca0abe3dSGeert Uytterhoeven 	cyttsp4_start_wd_timer(cd);
1820ca0abe3dSGeert Uytterhoeven 
1821ca0abe3dSGeert Uytterhoeven 	return 0;
1822ca0abe3dSGeert Uytterhoeven }
1823ca0abe3dSGeert Uytterhoeven 
cyttsp4_core_wake(struct cyttsp4 * cd)1824ca0abe3dSGeert Uytterhoeven static int cyttsp4_core_wake(struct cyttsp4 *cd)
1825ca0abe3dSGeert Uytterhoeven {
1826ca0abe3dSGeert Uytterhoeven 	int rc;
1827ca0abe3dSGeert Uytterhoeven 
1828ca0abe3dSGeert Uytterhoeven 	rc = cyttsp4_request_exclusive(cd, cd->dev,
1829ca0abe3dSGeert Uytterhoeven 			CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
1830ca0abe3dSGeert Uytterhoeven 	if (rc < 0) {
1831ca0abe3dSGeert Uytterhoeven 		dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
1832ca0abe3dSGeert Uytterhoeven 				__func__, cd->exclusive_dev, cd->dev);
1833ca0abe3dSGeert Uytterhoeven 		return 0;
1834ca0abe3dSGeert Uytterhoeven 	}
1835ca0abe3dSGeert Uytterhoeven 
1836ca0abe3dSGeert Uytterhoeven 	rc = cyttsp4_core_wake_(cd);
1837ca0abe3dSGeert Uytterhoeven 
1838ca0abe3dSGeert Uytterhoeven 	if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
1839ca0abe3dSGeert Uytterhoeven 		dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
1840ca0abe3dSGeert Uytterhoeven 	else
1841ca0abe3dSGeert Uytterhoeven 		dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
1842ca0abe3dSGeert Uytterhoeven 
1843ca0abe3dSGeert Uytterhoeven 	return rc;
1844ca0abe3dSGeert Uytterhoeven }
1845ca0abe3dSGeert Uytterhoeven 
cyttsp4_core_suspend(struct device * dev)184617fb1563SFerruh Yigit static int cyttsp4_core_suspend(struct device *dev)
184717fb1563SFerruh Yigit {
184817fb1563SFerruh Yigit 	struct cyttsp4 *cd = dev_get_drvdata(dev);
184917fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
185017fb1563SFerruh Yigit 	int rc;
185117fb1563SFerruh Yigit 
185217fb1563SFerruh Yigit 	md->is_suspended = true;
185317fb1563SFerruh Yigit 
185417fb1563SFerruh Yigit 	rc = cyttsp4_core_sleep(cd);
185517fb1563SFerruh Yigit 	if (rc < 0) {
185617fb1563SFerruh Yigit 		dev_err(dev, "%s: Error on sleep\n", __func__);
185717fb1563SFerruh Yigit 		return -EAGAIN;
185817fb1563SFerruh Yigit 	}
185917fb1563SFerruh Yigit 	return 0;
186017fb1563SFerruh Yigit }
186117fb1563SFerruh Yigit 
cyttsp4_core_resume(struct device * dev)186217fb1563SFerruh Yigit static int cyttsp4_core_resume(struct device *dev)
186317fb1563SFerruh Yigit {
186417fb1563SFerruh Yigit 	struct cyttsp4 *cd = dev_get_drvdata(dev);
186517fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
186617fb1563SFerruh Yigit 	int rc;
186717fb1563SFerruh Yigit 
186817fb1563SFerruh Yigit 	md->is_suspended = false;
186917fb1563SFerruh Yigit 
187017fb1563SFerruh Yigit 	rc = cyttsp4_core_wake(cd);
187117fb1563SFerruh Yigit 	if (rc < 0) {
187217fb1563SFerruh Yigit 		dev_err(dev, "%s: Error on wake\n", __func__);
187317fb1563SFerruh Yigit 		return -EAGAIN;
187417fb1563SFerruh Yigit 	}
187517fb1563SFerruh Yigit 
187617fb1563SFerruh Yigit 	return 0;
187717fb1563SFerruh Yigit }
187817fb1563SFerruh Yigit 
1879ebbdbef2SJonathan Cameron EXPORT_GPL_RUNTIME_DEV_PM_OPS(cyttsp4_pm_ops,
1880ebbdbef2SJonathan Cameron 			      cyttsp4_core_suspend, cyttsp4_core_resume, NULL);
188117fb1563SFerruh Yigit 
cyttsp4_mt_open(struct input_dev * input)188217fb1563SFerruh Yigit static int cyttsp4_mt_open(struct input_dev *input)
188317fb1563SFerruh Yigit {
188417fb1563SFerruh Yigit 	pm_runtime_get(input->dev.parent);
188517fb1563SFerruh Yigit 	return 0;
188617fb1563SFerruh Yigit }
188717fb1563SFerruh Yigit 
cyttsp4_mt_close(struct input_dev * input)188817fb1563SFerruh Yigit static void cyttsp4_mt_close(struct input_dev *input)
188917fb1563SFerruh Yigit {
189017fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = input_get_drvdata(input);
189117fb1563SFerruh Yigit 	mutex_lock(&md->report_lock);
189217fb1563SFerruh Yigit 	if (!md->is_suspended)
189317fb1563SFerruh Yigit 		pm_runtime_put(input->dev.parent);
189417fb1563SFerruh Yigit 	mutex_unlock(&md->report_lock);
189517fb1563SFerruh Yigit }
189617fb1563SFerruh Yigit 
189717fb1563SFerruh Yigit 
cyttsp4_setup_input_device(struct cyttsp4 * cd)189817fb1563SFerruh Yigit static int cyttsp4_setup_input_device(struct cyttsp4 *cd)
189917fb1563SFerruh Yigit {
190017fb1563SFerruh Yigit 	struct device *dev = cd->dev;
190117fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
190217fb1563SFerruh Yigit 	int signal = CY_IGNORE_VALUE;
190317fb1563SFerruh Yigit 	int max_x, max_y, max_p, min, max;
190417fb1563SFerruh Yigit 	int max_x_tmp, max_y_tmp;
190517fb1563SFerruh Yigit 	int i;
190617fb1563SFerruh Yigit 	int rc;
190717fb1563SFerruh Yigit 
190817fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
190917fb1563SFerruh Yigit 	__set_bit(EV_ABS, md->input->evbit);
191017fb1563SFerruh Yigit 	__set_bit(EV_REL, md->input->evbit);
191117fb1563SFerruh Yigit 	__set_bit(EV_KEY, md->input->evbit);
191217fb1563SFerruh Yigit 
191317fb1563SFerruh Yigit 	max_x_tmp = md->si->si_ofs.max_x;
191417fb1563SFerruh Yigit 	max_y_tmp = md->si->si_ofs.max_y;
191517fb1563SFerruh Yigit 
191617fb1563SFerruh Yigit 	/* get maximum values from the sysinfo data */
191717fb1563SFerruh Yigit 	if (md->pdata->flags & CY_FLAG_FLIP) {
191817fb1563SFerruh Yigit 		max_x = max_y_tmp - 1;
191917fb1563SFerruh Yigit 		max_y = max_x_tmp - 1;
192017fb1563SFerruh Yigit 	} else {
192117fb1563SFerruh Yigit 		max_x = max_x_tmp - 1;
192217fb1563SFerruh Yigit 		max_y = max_y_tmp - 1;
192317fb1563SFerruh Yigit 	}
192417fb1563SFerruh Yigit 	max_p = md->si->si_ofs.max_p;
192517fb1563SFerruh Yigit 
192617fb1563SFerruh Yigit 	/* set event signal capabilities */
192717fb1563SFerruh Yigit 	for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
192817fb1563SFerruh Yigit 		signal = md->pdata->frmwrk->abs
192917fb1563SFerruh Yigit 			[(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST];
193017fb1563SFerruh Yigit 		if (signal != CY_IGNORE_VALUE) {
193117fb1563SFerruh Yigit 			__set_bit(signal, md->input->absbit);
193217fb1563SFerruh Yigit 			min = md->pdata->frmwrk->abs
193317fb1563SFerruh Yigit 				[(i * CY_NUM_ABS_SET) + CY_MIN_OST];
193417fb1563SFerruh Yigit 			max = md->pdata->frmwrk->abs
193517fb1563SFerruh Yigit 				[(i * CY_NUM_ABS_SET) + CY_MAX_OST];
193617fb1563SFerruh Yigit 			if (i == CY_ABS_ID_OST) {
193717fb1563SFerruh Yigit 				/* shift track ids down to start at 0 */
193817fb1563SFerruh Yigit 				max = max - min;
193917fb1563SFerruh Yigit 				min = min - min;
194017fb1563SFerruh Yigit 			} else if (i == CY_ABS_X_OST)
194117fb1563SFerruh Yigit 				max = max_x;
194217fb1563SFerruh Yigit 			else if (i == CY_ABS_Y_OST)
194317fb1563SFerruh Yigit 				max = max_y;
194417fb1563SFerruh Yigit 			else if (i == CY_ABS_P_OST)
194517fb1563SFerruh Yigit 				max = max_p;
194617fb1563SFerruh Yigit 			input_set_abs_params(md->input, signal, min, max,
194717fb1563SFerruh Yigit 				md->pdata->frmwrk->abs
194817fb1563SFerruh Yigit 				[(i * CY_NUM_ABS_SET) + CY_FUZZ_OST],
194917fb1563SFerruh Yigit 				md->pdata->frmwrk->abs
195017fb1563SFerruh Yigit 				[(i * CY_NUM_ABS_SET) + CY_FLAT_OST]);
195117fb1563SFerruh Yigit 			dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
195217fb1563SFerruh Yigit 				__func__, signal, min, max);
195317fb1563SFerruh Yigit 			if ((i == CY_ABS_ID_OST) &&
195417fb1563SFerruh Yigit 				(md->si->si_ofs.tch_rec_size <
195517fb1563SFerruh Yigit 				CY_TMA4XX_TCH_REC_SIZE))
195617fb1563SFerruh Yigit 				break;
195717fb1563SFerruh Yigit 		}
195817fb1563SFerruh Yigit 	}
195917fb1563SFerruh Yigit 
196017fb1563SFerruh Yigit 	input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max,
196117fb1563SFerruh Yigit 			INPUT_MT_DIRECT);
196217fb1563SFerruh Yigit 	rc = input_register_device(md->input);
196317fb1563SFerruh Yigit 	if (rc < 0)
196417fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, failed register input device r=%d\n",
196517fb1563SFerruh Yigit 			__func__, rc);
196617fb1563SFerruh Yigit 	return rc;
196717fb1563SFerruh Yigit }
196817fb1563SFerruh Yigit 
cyttsp4_mt_probe(struct cyttsp4 * cd)196917fb1563SFerruh Yigit static int cyttsp4_mt_probe(struct cyttsp4 *cd)
197017fb1563SFerruh Yigit {
197117fb1563SFerruh Yigit 	struct device *dev = cd->dev;
197217fb1563SFerruh Yigit 	struct cyttsp4_mt_data *md = &cd->md;
197317fb1563SFerruh Yigit 	struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata;
197417fb1563SFerruh Yigit 	int rc = 0;
197517fb1563SFerruh Yigit 
197617fb1563SFerruh Yigit 	mutex_init(&md->report_lock);
197717fb1563SFerruh Yigit 	md->pdata = pdata;
197817fb1563SFerruh Yigit 	/* Create the input device and register it. */
197917fb1563SFerruh Yigit 	dev_vdbg(dev, "%s: Create the input device and register it\n",
198017fb1563SFerruh Yigit 		__func__);
198117fb1563SFerruh Yigit 	md->input = input_allocate_device();
198217fb1563SFerruh Yigit 	if (md->input == NULL) {
198317fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, failed to allocate input device\n",
198417fb1563SFerruh Yigit 			__func__);
198517fb1563SFerruh Yigit 		rc = -ENOSYS;
198617fb1563SFerruh Yigit 		goto error_alloc_failed;
198717fb1563SFerruh Yigit 	}
198817fb1563SFerruh Yigit 
198917fb1563SFerruh Yigit 	md->input->name = pdata->inp_dev_name;
199017fb1563SFerruh Yigit 	scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev));
199117fb1563SFerruh Yigit 	md->input->phys = md->phys;
199217fb1563SFerruh Yigit 	md->input->id.bustype = cd->bus_ops->bustype;
199317fb1563SFerruh Yigit 	md->input->dev.parent = dev;
199417fb1563SFerruh Yigit 	md->input->open = cyttsp4_mt_open;
199517fb1563SFerruh Yigit 	md->input->close = cyttsp4_mt_close;
199617fb1563SFerruh Yigit 	input_set_drvdata(md->input, md);
199717fb1563SFerruh Yigit 
199817fb1563SFerruh Yigit 	/* get sysinfo */
199917fb1563SFerruh Yigit 	md->si = &cd->sysinfo;
200017fb1563SFerruh Yigit 
200117fb1563SFerruh Yigit 	rc = cyttsp4_setup_input_device(cd);
200217fb1563SFerruh Yigit 	if (rc)
200317fb1563SFerruh Yigit 		goto error_init_input;
200417fb1563SFerruh Yigit 
200517fb1563SFerruh Yigit 	return 0;
200617fb1563SFerruh Yigit 
200717fb1563SFerruh Yigit error_init_input:
200817fb1563SFerruh Yigit 	input_free_device(md->input);
200917fb1563SFerruh Yigit error_alloc_failed:
201017fb1563SFerruh Yigit 	dev_err(dev, "%s failed.\n", __func__);
201117fb1563SFerruh Yigit 	return rc;
201217fb1563SFerruh Yigit }
201317fb1563SFerruh Yigit 
cyttsp4_probe(const struct cyttsp4_bus_ops * ops,struct device * dev,u16 irq,size_t xfer_buf_size)201417fb1563SFerruh Yigit struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
201517fb1563SFerruh Yigit 		struct device *dev, u16 irq, size_t xfer_buf_size)
201617fb1563SFerruh Yigit {
201717fb1563SFerruh Yigit 	struct cyttsp4 *cd;
201817fb1563SFerruh Yigit 	struct cyttsp4_platform_data *pdata = dev_get_platdata(dev);
201917fb1563SFerruh Yigit 	unsigned long irq_flags;
202017fb1563SFerruh Yigit 	int rc = 0;
202117fb1563SFerruh Yigit 
202217fb1563SFerruh Yigit 	if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) {
202317fb1563SFerruh Yigit 		dev_err(dev, "%s: Missing platform data\n", __func__);
202417fb1563SFerruh Yigit 		rc = -ENODEV;
202517fb1563SFerruh Yigit 		goto error_no_pdata;
202617fb1563SFerruh Yigit 	}
202717fb1563SFerruh Yigit 
202817fb1563SFerruh Yigit 	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
202917fb1563SFerruh Yigit 	if (!cd) {
203017fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, kzalloc\n", __func__);
203117fb1563SFerruh Yigit 		rc = -ENOMEM;
203217fb1563SFerruh Yigit 		goto error_alloc_data;
203317fb1563SFerruh Yigit 	}
203417fb1563SFerruh Yigit 
203517fb1563SFerruh Yigit 	cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL);
203617fb1563SFerruh Yigit 	if (!cd->xfer_buf) {
203717fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, kzalloc\n", __func__);
203817fb1563SFerruh Yigit 		rc = -ENOMEM;
2039394fc05bSDan Carpenter 		goto error_free_cd;
204017fb1563SFerruh Yigit 	}
204117fb1563SFerruh Yigit 
204217fb1563SFerruh Yigit 	/* Initialize device info */
204317fb1563SFerruh Yigit 	cd->dev = dev;
204417fb1563SFerruh Yigit 	cd->pdata = pdata;
204517fb1563SFerruh Yigit 	cd->cpdata = pdata->core_pdata;
204617fb1563SFerruh Yigit 	cd->bus_ops = ops;
204717fb1563SFerruh Yigit 
204817fb1563SFerruh Yigit 	/* Initialize mutexes and spinlocks */
204917fb1563SFerruh Yigit 	mutex_init(&cd->system_lock);
205017fb1563SFerruh Yigit 	mutex_init(&cd->adap_lock);
205117fb1563SFerruh Yigit 
205217fb1563SFerruh Yigit 	/* Initialize wait queue */
205317fb1563SFerruh Yigit 	init_waitqueue_head(&cd->wait_q);
205417fb1563SFerruh Yigit 
205517fb1563SFerruh Yigit 	/* Initialize works */
205617fb1563SFerruh Yigit 	INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function);
205717fb1563SFerruh Yigit 	INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work);
205817fb1563SFerruh Yigit 
205917fb1563SFerruh Yigit 	/* Initialize IRQ */
206017fb1563SFerruh Yigit 	cd->irq = gpio_to_irq(cd->cpdata->irq_gpio);
206117fb1563SFerruh Yigit 	if (cd->irq < 0) {
206217fb1563SFerruh Yigit 		rc = -EINVAL;
206357961e3bSFerruh Yigit 		goto error_free_xfer;
206417fb1563SFerruh Yigit 	}
206517fb1563SFerruh Yigit 
206617fb1563SFerruh Yigit 	dev_set_drvdata(dev, cd);
206717fb1563SFerruh Yigit 
206817fb1563SFerruh Yigit 	/* Call platform init function */
206917fb1563SFerruh Yigit 	if (cd->cpdata->init) {
207017fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: Init HW\n", __func__);
207117fb1563SFerruh Yigit 		rc = cd->cpdata->init(cd->cpdata, 1, cd->dev);
207217fb1563SFerruh Yigit 	} else {
207317fb1563SFerruh Yigit 		dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__);
207417fb1563SFerruh Yigit 		rc = 0;
207517fb1563SFerruh Yigit 	}
207617fb1563SFerruh Yigit 	if (rc < 0)
207717fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc);
207817fb1563SFerruh Yigit 
207917fb1563SFerruh Yigit 	dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq);
208017fb1563SFerruh Yigit 	if (cd->cpdata->level_irq_udelay > 0)
208117fb1563SFerruh Yigit 		/* use level triggered interrupts */
208217fb1563SFerruh Yigit 		irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
208317fb1563SFerruh Yigit 	else
208417fb1563SFerruh Yigit 		/* use edge triggered interrupts */
208517fb1563SFerruh Yigit 		irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
208617fb1563SFerruh Yigit 
208717fb1563SFerruh Yigit 	rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags,
208817fb1563SFerruh Yigit 		dev_name(dev), cd);
208917fb1563SFerruh Yigit 	if (rc < 0) {
209017fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, could not request irq\n", __func__);
209117fb1563SFerruh Yigit 		goto error_request_irq;
209217fb1563SFerruh Yigit 	}
209317fb1563SFerruh Yigit 
209417fb1563SFerruh Yigit 	/* Setup watchdog timer */
2095ee03e3f0SKees Cook 	timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
209617fb1563SFerruh Yigit 
209717fb1563SFerruh Yigit 	/*
209817fb1563SFerruh Yigit 	 * call startup directly to ensure that the device
209917fb1563SFerruh Yigit 	 * is tested before leaving the probe
210017fb1563SFerruh Yigit 	 */
210117fb1563SFerruh Yigit 	rc = cyttsp4_startup(cd);
210217fb1563SFerruh Yigit 
210317fb1563SFerruh Yigit 	/* Do not fail probe if startup fails but the device is detected */
210417fb1563SFerruh Yigit 	if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) {
210517fb1563SFerruh Yigit 		dev_err(cd->dev, "%s: Fail initial startup r=%d\n",
210617fb1563SFerruh Yigit 			__func__, rc);
210717fb1563SFerruh Yigit 		goto error_startup;
210817fb1563SFerruh Yigit 	}
210917fb1563SFerruh Yigit 
211017fb1563SFerruh Yigit 	rc = cyttsp4_mt_probe(cd);
211117fb1563SFerruh Yigit 	if (rc < 0) {
211217fb1563SFerruh Yigit 		dev_err(dev, "%s: Error, fail mt probe\n", __func__);
211317fb1563SFerruh Yigit 		goto error_startup;
211417fb1563SFerruh Yigit 	}
211517fb1563SFerruh Yigit 
211617fb1563SFerruh Yigit 	pm_runtime_enable(dev);
211717fb1563SFerruh Yigit 
211817fb1563SFerruh Yigit 	return cd;
211917fb1563SFerruh Yigit 
212017fb1563SFerruh Yigit error_startup:
212117fb1563SFerruh Yigit 	cancel_work_sync(&cd->startup_work);
212217fb1563SFerruh Yigit 	cyttsp4_stop_wd_timer(cd);
212317fb1563SFerruh Yigit 	pm_runtime_disable(dev);
212417fb1563SFerruh Yigit 	cyttsp4_free_si_ptrs(cd);
212517fb1563SFerruh Yigit 	free_irq(cd->irq, cd);
212617fb1563SFerruh Yigit error_request_irq:
212717fb1563SFerruh Yigit 	if (cd->cpdata->init)
212817fb1563SFerruh Yigit 		cd->cpdata->init(cd->cpdata, 0, dev);
212957961e3bSFerruh Yigit error_free_xfer:
213057961e3bSFerruh Yigit 	kfree(cd->xfer_buf);
2131394fc05bSDan Carpenter error_free_cd:
213217fb1563SFerruh Yigit 	kfree(cd);
213317fb1563SFerruh Yigit error_alloc_data:
213417fb1563SFerruh Yigit error_no_pdata:
213517fb1563SFerruh Yigit 	dev_err(dev, "%s failed.\n", __func__);
213617fb1563SFerruh Yigit 	return ERR_PTR(rc);
213717fb1563SFerruh Yigit }
213817fb1563SFerruh Yigit EXPORT_SYMBOL_GPL(cyttsp4_probe);
213917fb1563SFerruh Yigit 
cyttsp4_mt_release(struct cyttsp4_mt_data * md)214017fb1563SFerruh Yigit static void cyttsp4_mt_release(struct cyttsp4_mt_data *md)
214117fb1563SFerruh Yigit {
214217fb1563SFerruh Yigit 	input_unregister_device(md->input);
214317fb1563SFerruh Yigit 	input_set_drvdata(md->input, NULL);
214417fb1563SFerruh Yigit }
214517fb1563SFerruh Yigit 
cyttsp4_remove(struct cyttsp4 * cd)214617fb1563SFerruh Yigit int cyttsp4_remove(struct cyttsp4 *cd)
214717fb1563SFerruh Yigit {
214817fb1563SFerruh Yigit 	struct device *dev = cd->dev;
214917fb1563SFerruh Yigit 
215017fb1563SFerruh Yigit 	cyttsp4_mt_release(&cd->md);
215117fb1563SFerruh Yigit 
215217fb1563SFerruh Yigit 	/*
215317fb1563SFerruh Yigit 	 * Suspend the device before freeing the startup_work and stopping
215417fb1563SFerruh Yigit 	 * the watchdog since sleep function restarts watchdog on failure
215517fb1563SFerruh Yigit 	 */
215617fb1563SFerruh Yigit 	pm_runtime_suspend(dev);
215717fb1563SFerruh Yigit 	pm_runtime_disable(dev);
215817fb1563SFerruh Yigit 
215917fb1563SFerruh Yigit 	cancel_work_sync(&cd->startup_work);
216017fb1563SFerruh Yigit 
216117fb1563SFerruh Yigit 	cyttsp4_stop_wd_timer(cd);
216217fb1563SFerruh Yigit 
216317fb1563SFerruh Yigit 	free_irq(cd->irq, cd);
216417fb1563SFerruh Yigit 	if (cd->cpdata->init)
216517fb1563SFerruh Yigit 		cd->cpdata->init(cd->cpdata, 0, dev);
216617fb1563SFerruh Yigit 	cyttsp4_free_si_ptrs(cd);
216717fb1563SFerruh Yigit 	kfree(cd);
216817fb1563SFerruh Yigit 	return 0;
216917fb1563SFerruh Yigit }
217017fb1563SFerruh Yigit EXPORT_SYMBOL_GPL(cyttsp4_remove);
217117fb1563SFerruh Yigit 
217217fb1563SFerruh Yigit MODULE_LICENSE("GPL");
217317fb1563SFerruh Yigit MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver");
217417fb1563SFerruh Yigit MODULE_AUTHOR("Cypress");
2175