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