108dbd0f8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24065d1e7SJavier Martinez Canillas /*
34065d1e7SJavier Martinez Canillas * Core Source for:
44065d1e7SJavier Martinez Canillas * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
54065d1e7SJavier Martinez Canillas * For use with Cypress Txx3xx parts.
64065d1e7SJavier Martinez Canillas * Supported parts include:
74065d1e7SJavier Martinez Canillas * CY8CTST341
84065d1e7SJavier Martinez Canillas * CY8CTMA340
94065d1e7SJavier Martinez Canillas *
104065d1e7SJavier Martinez Canillas * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
114065d1e7SJavier Martinez Canillas * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
124065d1e7SJavier Martinez Canillas *
134065d1e7SJavier Martinez Canillas * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
144065d1e7SJavier Martinez Canillas */
154065d1e7SJavier Martinez Canillas
164065d1e7SJavier Martinez Canillas #include <linux/delay.h>
174065d1e7SJavier Martinez Canillas #include <linux/input.h>
184065d1e7SJavier Martinez Canillas #include <linux/input/mt.h>
19707b61bbSOreste Salerno #include <linux/input/touchscreen.h>
204065d1e7SJavier Martinez Canillas #include <linux/interrupt.h>
214065d1e7SJavier Martinez Canillas #include <linux/slab.h>
22707b61bbSOreste Salerno #include <linux/property.h>
23707b61bbSOreste Salerno #include <linux/gpio/consumer.h>
246cf3b3abSLinus Walleij #include <linux/regulator/consumer.h>
254065d1e7SJavier Martinez Canillas
264065d1e7SJavier Martinez Canillas #include "cyttsp_core.h"
274065d1e7SJavier Martinez Canillas
284065d1e7SJavier Martinez Canillas /* Bootloader number of command keys */
294065d1e7SJavier Martinez Canillas #define CY_NUM_BL_KEYS 8
304065d1e7SJavier Martinez Canillas
314065d1e7SJavier Martinez Canillas /* helpers */
324065d1e7SJavier Martinez Canillas #define GET_NUM_TOUCHES(x) ((x) & 0x0F)
334065d1e7SJavier Martinez Canillas #define IS_LARGE_AREA(x) (((x) & 0x10) >> 4)
344065d1e7SJavier Martinez Canillas #define IS_BAD_PKT(x) ((x) & 0x20)
354065d1e7SJavier Martinez Canillas #define IS_VALID_APP(x) ((x) & 0x01)
364065d1e7SJavier Martinez Canillas #define IS_OPERATIONAL_ERR(x) ((x) & 0x3F)
374065d1e7SJavier Martinez Canillas #define GET_HSTMODE(reg) (((reg) & 0x70) >> 4)
384065d1e7SJavier Martinez Canillas #define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
394065d1e7SJavier Martinez Canillas
404065d1e7SJavier Martinez Canillas #define CY_REG_BASE 0x00
414065d1e7SJavier Martinez Canillas #define CY_REG_ACT_DIST 0x1E
424065d1e7SJavier Martinez Canillas #define CY_REG_ACT_INTRVL 0x1D
434065d1e7SJavier Martinez Canillas #define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1)
444065d1e7SJavier Martinez Canillas #define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1)
454065d1e7SJavier Martinez Canillas #define CY_MAXZ 255
464065d1e7SJavier Martinez Canillas #define CY_DELAY_DFLT 20 /* ms */
474065d1e7SJavier Martinez Canillas #define CY_DELAY_MAX 500
48d27ac0fbSDmitry Torokhov /* Active distance in pixels for a gesture to be reported */
49d27ac0fbSDmitry Torokhov #define CY_ACT_DIST_DFLT 0xF8 /* pixels */
50707b61bbSOreste Salerno #define CY_ACT_DIST_MASK 0x0F
51d27ac0fbSDmitry Torokhov /* Active Power state scanning/processing refresh interval */
52d27ac0fbSDmitry Torokhov #define CY_ACT_INTRVL_DFLT 0x00 /* ms */
53d27ac0fbSDmitry Torokhov /* Low Power state scanning/processing refresh interval */
54d27ac0fbSDmitry Torokhov #define CY_LP_INTRVL_DFLT 0x0A /* ms */
55d27ac0fbSDmitry Torokhov /* touch timeout for the Active power */
56d27ac0fbSDmitry Torokhov #define CY_TCH_TMOUT_DFLT 0xFF /* ms */
574065d1e7SJavier Martinez Canillas #define CY_HNDSHK_BIT 0x80
584065d1e7SJavier Martinez Canillas /* device mode bits */
594065d1e7SJavier Martinez Canillas #define CY_OPERATE_MODE 0x00
604065d1e7SJavier Martinez Canillas #define CY_SYSINFO_MODE 0x10
614065d1e7SJavier Martinez Canillas /* power mode select bits */
624065d1e7SJavier Martinez Canillas #define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */
634065d1e7SJavier Martinez Canillas #define CY_DEEP_SLEEP_MODE 0x02
644065d1e7SJavier Martinez Canillas #define CY_LOW_POWER_MODE 0x04
654065d1e7SJavier Martinez Canillas
664065d1e7SJavier Martinez Canillas /* Slots management */
674065d1e7SJavier Martinez Canillas #define CY_MAX_FINGER 4
684065d1e7SJavier Martinez Canillas #define CY_MAX_ID 16
694065d1e7SJavier Martinez Canillas
704065d1e7SJavier Martinez Canillas static const u8 bl_command[] = {
714065d1e7SJavier Martinez Canillas 0x00, /* file offset */
724065d1e7SJavier Martinez Canillas 0xFF, /* command */
734065d1e7SJavier Martinez Canillas 0xA5, /* exit bootloader command */
744065d1e7SJavier Martinez Canillas 0, 1, 2, 3, 4, 5, 6, 7 /* default keys */
754065d1e7SJavier Martinez Canillas };
764065d1e7SJavier Martinez Canillas
ttsp_read_block_data(struct cyttsp * ts,u8 command,u8 length,void * buf)774065d1e7SJavier Martinez Canillas static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
784065d1e7SJavier Martinez Canillas u8 length, void *buf)
794065d1e7SJavier Martinez Canillas {
804065d1e7SJavier Martinez Canillas int error;
814065d1e7SJavier Martinez Canillas int tries;
824065d1e7SJavier Martinez Canillas
834065d1e7SJavier Martinez Canillas for (tries = 0; tries < CY_NUM_RETRY; tries++) {
849664877eSFerruh Yigit error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command,
859664877eSFerruh Yigit length, buf);
864065d1e7SJavier Martinez Canillas if (!error)
874065d1e7SJavier Martinez Canillas return 0;
884065d1e7SJavier Martinez Canillas
894065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT);
904065d1e7SJavier Martinez Canillas }
914065d1e7SJavier Martinez Canillas
924065d1e7SJavier Martinez Canillas return -EIO;
934065d1e7SJavier Martinez Canillas }
944065d1e7SJavier Martinez Canillas
ttsp_write_block_data(struct cyttsp * ts,u8 command,u8 length,void * buf)954065d1e7SJavier Martinez Canillas static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
964065d1e7SJavier Martinez Canillas u8 length, void *buf)
974065d1e7SJavier Martinez Canillas {
984065d1e7SJavier Martinez Canillas int error;
994065d1e7SJavier Martinez Canillas int tries;
1004065d1e7SJavier Martinez Canillas
1014065d1e7SJavier Martinez Canillas for (tries = 0; tries < CY_NUM_RETRY; tries++) {
1029664877eSFerruh Yigit error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command,
1039664877eSFerruh Yigit length, buf);
1044065d1e7SJavier Martinez Canillas if (!error)
1054065d1e7SJavier Martinez Canillas return 0;
1064065d1e7SJavier Martinez Canillas
1074065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT);
1084065d1e7SJavier Martinez Canillas }
1094065d1e7SJavier Martinez Canillas
1104065d1e7SJavier Martinez Canillas return -EIO;
1114065d1e7SJavier Martinez Canillas }
1124065d1e7SJavier Martinez Canillas
ttsp_send_command(struct cyttsp * ts,u8 cmd)1134065d1e7SJavier Martinez Canillas static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
1144065d1e7SJavier Martinez Canillas {
1154065d1e7SJavier Martinez Canillas return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
1164065d1e7SJavier Martinez Canillas }
1174065d1e7SJavier Martinez Canillas
cyttsp_handshake(struct cyttsp * ts)118fbd5e77eSFerruh Yigit static int cyttsp_handshake(struct cyttsp *ts)
119fbd5e77eSFerruh Yigit {
120707b61bbSOreste Salerno if (ts->use_hndshk)
121fbd5e77eSFerruh Yigit return ttsp_send_command(ts,
122fbd5e77eSFerruh Yigit ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
123fbd5e77eSFerruh Yigit
124fbd5e77eSFerruh Yigit return 0;
125fbd5e77eSFerruh Yigit }
126fbd5e77eSFerruh Yigit
cyttsp_load_bl_regs(struct cyttsp * ts)1274065d1e7SJavier Martinez Canillas static int cyttsp_load_bl_regs(struct cyttsp *ts)
1284065d1e7SJavier Martinez Canillas {
1294065d1e7SJavier Martinez Canillas memset(&ts->bl_data, 0, sizeof(ts->bl_data));
1304065d1e7SJavier Martinez Canillas ts->bl_data.bl_status = 0x10;
1314065d1e7SJavier Martinez Canillas
1324065d1e7SJavier Martinez Canillas return ttsp_read_block_data(ts, CY_REG_BASE,
1334065d1e7SJavier Martinez Canillas sizeof(ts->bl_data), &ts->bl_data);
1344065d1e7SJavier Martinez Canillas }
1354065d1e7SJavier Martinez Canillas
cyttsp_exit_bl_mode(struct cyttsp * ts)1364065d1e7SJavier Martinez Canillas static int cyttsp_exit_bl_mode(struct cyttsp *ts)
1374065d1e7SJavier Martinez Canillas {
1384065d1e7SJavier Martinez Canillas int error;
1394065d1e7SJavier Martinez Canillas u8 bl_cmd[sizeof(bl_command)];
1404065d1e7SJavier Martinez Canillas
1414065d1e7SJavier Martinez Canillas memcpy(bl_cmd, bl_command, sizeof(bl_command));
142707b61bbSOreste Salerno if (ts->bl_keys)
1434065d1e7SJavier Martinez Canillas memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
144707b61bbSOreste Salerno ts->bl_keys, CY_NUM_BL_KEYS);
1454065d1e7SJavier Martinez Canillas
1464065d1e7SJavier Martinez Canillas error = ttsp_write_block_data(ts, CY_REG_BASE,
1474065d1e7SJavier Martinez Canillas sizeof(bl_cmd), bl_cmd);
1484065d1e7SJavier Martinez Canillas if (error)
1494065d1e7SJavier Martinez Canillas return error;
1504065d1e7SJavier Martinez Canillas
1514065d1e7SJavier Martinez Canillas /* wait for TTSP Device to complete the operation */
1524065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT);
1534065d1e7SJavier Martinez Canillas
1544065d1e7SJavier Martinez Canillas error = cyttsp_load_bl_regs(ts);
1554065d1e7SJavier Martinez Canillas if (error)
1564065d1e7SJavier Martinez Canillas return error;
1574065d1e7SJavier Martinez Canillas
1584065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
1594065d1e7SJavier Martinez Canillas return -EIO;
1604065d1e7SJavier Martinez Canillas
1614065d1e7SJavier Martinez Canillas return 0;
1624065d1e7SJavier Martinez Canillas }
1634065d1e7SJavier Martinez Canillas
cyttsp_set_operational_mode(struct cyttsp * ts)1644065d1e7SJavier Martinez Canillas static int cyttsp_set_operational_mode(struct cyttsp *ts)
1654065d1e7SJavier Martinez Canillas {
1664065d1e7SJavier Martinez Canillas int error;
1674065d1e7SJavier Martinez Canillas
1684065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_OPERATE_MODE);
1694065d1e7SJavier Martinez Canillas if (error)
1704065d1e7SJavier Martinez Canillas return error;
1714065d1e7SJavier Martinez Canillas
1724065d1e7SJavier Martinez Canillas /* wait for TTSP Device to complete switch to Operational mode */
1734065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE,
1744065d1e7SJavier Martinez Canillas sizeof(ts->xy_data), &ts->xy_data);
1754065d1e7SJavier Martinez Canillas if (error)
1764065d1e7SJavier Martinez Canillas return error;
1774065d1e7SJavier Martinez Canillas
178fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts);
179fbd5e77eSFerruh Yigit if (error)
180fbd5e77eSFerruh Yigit return error;
181fbd5e77eSFerruh Yigit
1824065d1e7SJavier Martinez Canillas return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
1834065d1e7SJavier Martinez Canillas }
1844065d1e7SJavier Martinez Canillas
cyttsp_set_sysinfo_mode(struct cyttsp * ts)1854065d1e7SJavier Martinez Canillas static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
1864065d1e7SJavier Martinez Canillas {
1874065d1e7SJavier Martinez Canillas int error;
1884065d1e7SJavier Martinez Canillas
1894065d1e7SJavier Martinez Canillas memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
1904065d1e7SJavier Martinez Canillas
1914065d1e7SJavier Martinez Canillas /* switch to sysinfo mode */
1924065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_SYSINFO_MODE);
1934065d1e7SJavier Martinez Canillas if (error)
1944065d1e7SJavier Martinez Canillas return error;
1954065d1e7SJavier Martinez Canillas
1964065d1e7SJavier Martinez Canillas /* read sysinfo registers */
1974065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT);
1984065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
1994065d1e7SJavier Martinez Canillas &ts->sysinfo_data);
2004065d1e7SJavier Martinez Canillas if (error)
2014065d1e7SJavier Martinez Canillas return error;
2024065d1e7SJavier Martinez Canillas
203fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts);
204fbd5e77eSFerruh Yigit if (error)
205fbd5e77eSFerruh Yigit return error;
206fbd5e77eSFerruh Yigit
2074065d1e7SJavier Martinez Canillas if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
2084065d1e7SJavier Martinez Canillas return -EIO;
2094065d1e7SJavier Martinez Canillas
2104065d1e7SJavier Martinez Canillas return 0;
2114065d1e7SJavier Martinez Canillas }
2124065d1e7SJavier Martinez Canillas
cyttsp_set_sysinfo_regs(struct cyttsp * ts)2134065d1e7SJavier Martinez Canillas static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
2144065d1e7SJavier Martinez Canillas {
2154065d1e7SJavier Martinez Canillas int retval = 0;
2164065d1e7SJavier Martinez Canillas
217707b61bbSOreste Salerno if (ts->act_intrvl != CY_ACT_INTRVL_DFLT ||
218707b61bbSOreste Salerno ts->tch_tmout != CY_TCH_TMOUT_DFLT ||
219707b61bbSOreste Salerno ts->lp_intrvl != CY_LP_INTRVL_DFLT) {
2204065d1e7SJavier Martinez Canillas
2214065d1e7SJavier Martinez Canillas u8 intrvl_ray[] = {
222707b61bbSOreste Salerno ts->act_intrvl,
223707b61bbSOreste Salerno ts->tch_tmout,
224707b61bbSOreste Salerno ts->lp_intrvl
2254065d1e7SJavier Martinez Canillas };
2264065d1e7SJavier Martinez Canillas
2274065d1e7SJavier Martinez Canillas /* set intrvl registers */
2284065d1e7SJavier Martinez Canillas retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
2294065d1e7SJavier Martinez Canillas sizeof(intrvl_ray), intrvl_ray);
2304065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT);
2314065d1e7SJavier Martinez Canillas }
2324065d1e7SJavier Martinez Canillas
2334065d1e7SJavier Martinez Canillas return retval;
2344065d1e7SJavier Martinez Canillas }
2354065d1e7SJavier Martinez Canillas
cyttsp_hard_reset(struct cyttsp * ts)2368fb81d20SOreste Salerno static void cyttsp_hard_reset(struct cyttsp *ts)
2378fb81d20SOreste Salerno {
2388fb81d20SOreste Salerno if (ts->reset_gpio) {
239c61ac36fSLinus Walleij /*
240c61ac36fSLinus Walleij * According to the CY8CTMA340 datasheet page 21, the external
241c61ac36fSLinus Walleij * reset pulse width should be >= 1 ms. The datasheet does not
242c61ac36fSLinus Walleij * specify how long we have to wait after reset but a vendor
243c61ac36fSLinus Walleij * tree specifies 5 ms here.
244c61ac36fSLinus Walleij */
2458fb81d20SOreste Salerno gpiod_set_value_cansleep(ts->reset_gpio, 1);
246c61ac36fSLinus Walleij usleep_range(1000, 2000);
2478fb81d20SOreste Salerno gpiod_set_value_cansleep(ts->reset_gpio, 0);
248c61ac36fSLinus Walleij usleep_range(5000, 6000);
2498fb81d20SOreste Salerno }
2508fb81d20SOreste Salerno }
2518fb81d20SOreste Salerno
cyttsp_soft_reset(struct cyttsp * ts)2524065d1e7SJavier Martinez Canillas static int cyttsp_soft_reset(struct cyttsp *ts)
2534065d1e7SJavier Martinez Canillas {
2544065d1e7SJavier Martinez Canillas int retval;
2554065d1e7SJavier Martinez Canillas
2564065d1e7SJavier Martinez Canillas /* wait for interrupt to set ready completion */
25716735d02SWolfram Sang reinit_completion(&ts->bl_ready);
2584065d1e7SJavier Martinez Canillas ts->state = CY_BL_STATE;
2594065d1e7SJavier Martinez Canillas
2604065d1e7SJavier Martinez Canillas enable_irq(ts->irq);
2614065d1e7SJavier Martinez Canillas
2624065d1e7SJavier Martinez Canillas retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
26384c36ab7SLinus Walleij if (retval) {
26484c36ab7SLinus Walleij dev_err(ts->dev, "failed to send soft reset\n");
2654065d1e7SJavier Martinez Canillas goto out;
26684c36ab7SLinus Walleij }
2674065d1e7SJavier Martinez Canillas
26884c36ab7SLinus Walleij if (!wait_for_completion_timeout(&ts->bl_ready,
26984c36ab7SLinus Walleij msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX))) {
27084c36ab7SLinus Walleij dev_err(ts->dev, "timeout waiting for soft reset\n");
27184c36ab7SLinus Walleij retval = -EIO;
27284c36ab7SLinus Walleij }
2734065d1e7SJavier Martinez Canillas
2744065d1e7SJavier Martinez Canillas out:
2754065d1e7SJavier Martinez Canillas ts->state = CY_IDLE_STATE;
2764065d1e7SJavier Martinez Canillas disable_irq(ts->irq);
2774065d1e7SJavier Martinez Canillas return retval;
2784065d1e7SJavier Martinez Canillas }
2794065d1e7SJavier Martinez Canillas
cyttsp_act_dist_setup(struct cyttsp * ts)2804065d1e7SJavier Martinez Canillas static int cyttsp_act_dist_setup(struct cyttsp *ts)
2814065d1e7SJavier Martinez Canillas {
282707b61bbSOreste Salerno u8 act_dist_setup = ts->act_dist;
2834065d1e7SJavier Martinez Canillas
2844065d1e7SJavier Martinez Canillas /* Init gesture; active distance setup */
2854065d1e7SJavier Martinez Canillas return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
2864065d1e7SJavier Martinez Canillas sizeof(act_dist_setup), &act_dist_setup);
2874065d1e7SJavier Martinez Canillas }
2884065d1e7SJavier Martinez Canillas
cyttsp_extract_track_ids(struct cyttsp_xydata * xy_data,int * ids)2894065d1e7SJavier Martinez Canillas static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
2904065d1e7SJavier Martinez Canillas {
2914065d1e7SJavier Martinez Canillas ids[0] = xy_data->touch12_id >> 4;
2924065d1e7SJavier Martinez Canillas ids[1] = xy_data->touch12_id & 0xF;
2934065d1e7SJavier Martinez Canillas ids[2] = xy_data->touch34_id >> 4;
2944065d1e7SJavier Martinez Canillas ids[3] = xy_data->touch34_id & 0xF;
2954065d1e7SJavier Martinez Canillas }
2964065d1e7SJavier Martinez Canillas
cyttsp_get_tch(struct cyttsp_xydata * xy_data,int idx)2974065d1e7SJavier Martinez Canillas static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
2984065d1e7SJavier Martinez Canillas int idx)
2994065d1e7SJavier Martinez Canillas {
3004065d1e7SJavier Martinez Canillas switch (idx) {
3014065d1e7SJavier Martinez Canillas case 0:
3024065d1e7SJavier Martinez Canillas return &xy_data->tch1;
3034065d1e7SJavier Martinez Canillas case 1:
3044065d1e7SJavier Martinez Canillas return &xy_data->tch2;
3054065d1e7SJavier Martinez Canillas case 2:
3064065d1e7SJavier Martinez Canillas return &xy_data->tch3;
3074065d1e7SJavier Martinez Canillas case 3:
3084065d1e7SJavier Martinez Canillas return &xy_data->tch4;
3094065d1e7SJavier Martinez Canillas default:
3104065d1e7SJavier Martinez Canillas return NULL;
3114065d1e7SJavier Martinez Canillas }
3124065d1e7SJavier Martinez Canillas }
3134065d1e7SJavier Martinez Canillas
cyttsp_report_tchdata(struct cyttsp * ts)3144065d1e7SJavier Martinez Canillas static void cyttsp_report_tchdata(struct cyttsp *ts)
3154065d1e7SJavier Martinez Canillas {
3164065d1e7SJavier Martinez Canillas struct cyttsp_xydata *xy_data = &ts->xy_data;
3174065d1e7SJavier Martinez Canillas struct input_dev *input = ts->input;
3184065d1e7SJavier Martinez Canillas int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
3194065d1e7SJavier Martinez Canillas const struct cyttsp_tch *tch;
3204065d1e7SJavier Martinez Canillas int ids[CY_MAX_ID];
3214065d1e7SJavier Martinez Canillas int i;
3224065d1e7SJavier Martinez Canillas DECLARE_BITMAP(used, CY_MAX_ID);
3234065d1e7SJavier Martinez Canillas
3244065d1e7SJavier Martinez Canillas if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
3254065d1e7SJavier Martinez Canillas /* terminate all active tracks */
3264065d1e7SJavier Martinez Canillas num_tch = 0;
3274065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
3284065d1e7SJavier Martinez Canillas } else if (num_tch > CY_MAX_FINGER) {
3294065d1e7SJavier Martinez Canillas /* terminate all active tracks */
3304065d1e7SJavier Martinez Canillas num_tch = 0;
3314065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
3324065d1e7SJavier Martinez Canillas } else if (IS_BAD_PKT(xy_data->tt_mode)) {
3334065d1e7SJavier Martinez Canillas /* terminate all active tracks */
3344065d1e7SJavier Martinez Canillas num_tch = 0;
3354065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
3364065d1e7SJavier Martinez Canillas }
3374065d1e7SJavier Martinez Canillas
3384065d1e7SJavier Martinez Canillas cyttsp_extract_track_ids(xy_data, ids);
3394065d1e7SJavier Martinez Canillas
3404065d1e7SJavier Martinez Canillas bitmap_zero(used, CY_MAX_ID);
3414065d1e7SJavier Martinez Canillas
3424065d1e7SJavier Martinez Canillas for (i = 0; i < num_tch; i++) {
3434065d1e7SJavier Martinez Canillas tch = cyttsp_get_tch(xy_data, i);
3444065d1e7SJavier Martinez Canillas
3454065d1e7SJavier Martinez Canillas input_mt_slot(input, ids[i]);
3464065d1e7SJavier Martinez Canillas input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
3474065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
3484065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
3494065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
3504065d1e7SJavier Martinez Canillas
3514065d1e7SJavier Martinez Canillas __set_bit(ids[i], used);
3524065d1e7SJavier Martinez Canillas }
3534065d1e7SJavier Martinez Canillas
3544065d1e7SJavier Martinez Canillas for (i = 0; i < CY_MAX_ID; i++) {
3554065d1e7SJavier Martinez Canillas if (test_bit(i, used))
3564065d1e7SJavier Martinez Canillas continue;
3574065d1e7SJavier Martinez Canillas
3584065d1e7SJavier Martinez Canillas input_mt_slot(input, i);
3595fc70e35SJiada Wang input_mt_report_slot_inactive(input);
3604065d1e7SJavier Martinez Canillas }
3614065d1e7SJavier Martinez Canillas
3624065d1e7SJavier Martinez Canillas input_sync(input);
3634065d1e7SJavier Martinez Canillas }
3644065d1e7SJavier Martinez Canillas
cyttsp_irq(int irq,void * handle)3654065d1e7SJavier Martinez Canillas static irqreturn_t cyttsp_irq(int irq, void *handle)
3664065d1e7SJavier Martinez Canillas {
3674065d1e7SJavier Martinez Canillas struct cyttsp *ts = handle;
3684065d1e7SJavier Martinez Canillas int error;
3694065d1e7SJavier Martinez Canillas
3704065d1e7SJavier Martinez Canillas if (unlikely(ts->state == CY_BL_STATE)) {
3714065d1e7SJavier Martinez Canillas complete(&ts->bl_ready);
3724065d1e7SJavier Martinez Canillas goto out;
3734065d1e7SJavier Martinez Canillas }
3744065d1e7SJavier Martinez Canillas
3754065d1e7SJavier Martinez Canillas /* Get touch data from CYTTSP device */
3764065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE,
3774065d1e7SJavier Martinez Canillas sizeof(struct cyttsp_xydata), &ts->xy_data);
3784065d1e7SJavier Martinez Canillas if (error)
3794065d1e7SJavier Martinez Canillas goto out;
3804065d1e7SJavier Martinez Canillas
3814065d1e7SJavier Martinez Canillas /* provide flow control handshake */
382fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts);
3834065d1e7SJavier Martinez Canillas if (error)
3844065d1e7SJavier Martinez Canillas goto out;
3854065d1e7SJavier Martinez Canillas
3864065d1e7SJavier Martinez Canillas if (unlikely(ts->state == CY_IDLE_STATE))
3874065d1e7SJavier Martinez Canillas goto out;
3884065d1e7SJavier Martinez Canillas
3894065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
3904065d1e7SJavier Martinez Canillas /*
3914065d1e7SJavier Martinez Canillas * TTSP device has reset back to bootloader mode.
3924065d1e7SJavier Martinez Canillas * Restore to operational mode.
3934065d1e7SJavier Martinez Canillas */
3944065d1e7SJavier Martinez Canillas error = cyttsp_exit_bl_mode(ts);
3954065d1e7SJavier Martinez Canillas if (error) {
3964065d1e7SJavier Martinez Canillas dev_err(ts->dev,
3974065d1e7SJavier Martinez Canillas "Could not return to operational mode, err: %d\n",
3984065d1e7SJavier Martinez Canillas error);
3994065d1e7SJavier Martinez Canillas ts->state = CY_IDLE_STATE;
4004065d1e7SJavier Martinez Canillas }
4014065d1e7SJavier Martinez Canillas } else {
4024065d1e7SJavier Martinez Canillas cyttsp_report_tchdata(ts);
4034065d1e7SJavier Martinez Canillas }
4044065d1e7SJavier Martinez Canillas
4054065d1e7SJavier Martinez Canillas out:
4064065d1e7SJavier Martinez Canillas return IRQ_HANDLED;
4074065d1e7SJavier Martinez Canillas }
4084065d1e7SJavier Martinez Canillas
cyttsp_power_on(struct cyttsp * ts)4094065d1e7SJavier Martinez Canillas static int cyttsp_power_on(struct cyttsp *ts)
4104065d1e7SJavier Martinez Canillas {
4114065d1e7SJavier Martinez Canillas int error;
4124065d1e7SJavier Martinez Canillas
4134065d1e7SJavier Martinez Canillas error = cyttsp_soft_reset(ts);
4144065d1e7SJavier Martinez Canillas if (error)
4154065d1e7SJavier Martinez Canillas return error;
4164065d1e7SJavier Martinez Canillas
4174065d1e7SJavier Martinez Canillas error = cyttsp_load_bl_regs(ts);
4184065d1e7SJavier Martinez Canillas if (error)
4194065d1e7SJavier Martinez Canillas return error;
4204065d1e7SJavier Martinez Canillas
4214065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
4224065d1e7SJavier Martinez Canillas IS_VALID_APP(ts->bl_data.bl_status)) {
4234065d1e7SJavier Martinez Canillas error = cyttsp_exit_bl_mode(ts);
42439841136SLinus Walleij if (error) {
42539841136SLinus Walleij dev_err(ts->dev, "failed to exit bootloader mode\n");
4264065d1e7SJavier Martinez Canillas return error;
4274065d1e7SJavier Martinez Canillas }
42839841136SLinus Walleij }
4294065d1e7SJavier Martinez Canillas
4304065d1e7SJavier Martinez Canillas if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
4314065d1e7SJavier Martinez Canillas IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
4324065d1e7SJavier Martinez Canillas return -ENODEV;
4334065d1e7SJavier Martinez Canillas }
4344065d1e7SJavier Martinez Canillas
4354065d1e7SJavier Martinez Canillas error = cyttsp_set_sysinfo_mode(ts);
4364065d1e7SJavier Martinez Canillas if (error)
4374065d1e7SJavier Martinez Canillas return error;
4384065d1e7SJavier Martinez Canillas
4394065d1e7SJavier Martinez Canillas error = cyttsp_set_sysinfo_regs(ts);
4404065d1e7SJavier Martinez Canillas if (error)
4414065d1e7SJavier Martinez Canillas return error;
4424065d1e7SJavier Martinez Canillas
4434065d1e7SJavier Martinez Canillas error = cyttsp_set_operational_mode(ts);
4444065d1e7SJavier Martinez Canillas if (error)
4454065d1e7SJavier Martinez Canillas return error;
4464065d1e7SJavier Martinez Canillas
4474065d1e7SJavier Martinez Canillas /* init active distance */
4484065d1e7SJavier Martinez Canillas error = cyttsp_act_dist_setup(ts);
4494065d1e7SJavier Martinez Canillas if (error)
4504065d1e7SJavier Martinez Canillas return error;
4514065d1e7SJavier Martinez Canillas
4524065d1e7SJavier Martinez Canillas ts->state = CY_ACTIVE_STATE;
4534065d1e7SJavier Martinez Canillas
4544065d1e7SJavier Martinez Canillas return 0;
4554065d1e7SJavier Martinez Canillas }
4564065d1e7SJavier Martinez Canillas
cyttsp_enable(struct cyttsp * ts)4574065d1e7SJavier Martinez Canillas static int cyttsp_enable(struct cyttsp *ts)
4584065d1e7SJavier Martinez Canillas {
4594065d1e7SJavier Martinez Canillas int error;
4604065d1e7SJavier Martinez Canillas
4614065d1e7SJavier Martinez Canillas /*
4624065d1e7SJavier Martinez Canillas * The device firmware can wake on an I2C or SPI memory slave
4634065d1e7SJavier Martinez Canillas * address match. So just reading a register is sufficient to
4644065d1e7SJavier Martinez Canillas * wake up the device. The first read attempt will fail but it
4654065d1e7SJavier Martinez Canillas * will wake it up making the second read attempt successful.
4664065d1e7SJavier Martinez Canillas */
4674065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE,
4684065d1e7SJavier Martinez Canillas sizeof(ts->xy_data), &ts->xy_data);
4694065d1e7SJavier Martinez Canillas if (error)
4704065d1e7SJavier Martinez Canillas return error;
4714065d1e7SJavier Martinez Canillas
4724065d1e7SJavier Martinez Canillas if (GET_HSTMODE(ts->xy_data.hst_mode))
4734065d1e7SJavier Martinez Canillas return -EIO;
4744065d1e7SJavier Martinez Canillas
4754065d1e7SJavier Martinez Canillas enable_irq(ts->irq);
4764065d1e7SJavier Martinez Canillas
4774065d1e7SJavier Martinez Canillas return 0;
4784065d1e7SJavier Martinez Canillas }
4794065d1e7SJavier Martinez Canillas
cyttsp_disable(struct cyttsp * ts)4804065d1e7SJavier Martinez Canillas static int cyttsp_disable(struct cyttsp *ts)
4814065d1e7SJavier Martinez Canillas {
4824065d1e7SJavier Martinez Canillas int error;
4834065d1e7SJavier Martinez Canillas
4844065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
4854065d1e7SJavier Martinez Canillas if (error)
4864065d1e7SJavier Martinez Canillas return error;
4874065d1e7SJavier Martinez Canillas
4884065d1e7SJavier Martinez Canillas disable_irq(ts->irq);
4894065d1e7SJavier Martinez Canillas
4904065d1e7SJavier Martinez Canillas return 0;
4914065d1e7SJavier Martinez Canillas }
4924065d1e7SJavier Martinez Canillas
cyttsp_suspend(struct device * dev)493c3c2f2bcSJonathan Cameron static int cyttsp_suspend(struct device *dev)
4944065d1e7SJavier Martinez Canillas {
4954065d1e7SJavier Martinez Canillas struct cyttsp *ts = dev_get_drvdata(dev);
4964065d1e7SJavier Martinez Canillas int retval = 0;
4974065d1e7SJavier Martinez Canillas
4984065d1e7SJavier Martinez Canillas mutex_lock(&ts->input->mutex);
4994065d1e7SJavier Martinez Canillas
500d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(ts->input)) {
5014065d1e7SJavier Martinez Canillas retval = cyttsp_disable(ts);
5024065d1e7SJavier Martinez Canillas if (retval == 0)
5034065d1e7SJavier Martinez Canillas ts->suspended = true;
5044065d1e7SJavier Martinez Canillas }
5054065d1e7SJavier Martinez Canillas
5064065d1e7SJavier Martinez Canillas mutex_unlock(&ts->input->mutex);
5074065d1e7SJavier Martinez Canillas
5084065d1e7SJavier Martinez Canillas return retval;
5094065d1e7SJavier Martinez Canillas }
5104065d1e7SJavier Martinez Canillas
cyttsp_resume(struct device * dev)511c3c2f2bcSJonathan Cameron static int cyttsp_resume(struct device *dev)
5124065d1e7SJavier Martinez Canillas {
5134065d1e7SJavier Martinez Canillas struct cyttsp *ts = dev_get_drvdata(dev);
5144065d1e7SJavier Martinez Canillas
5154065d1e7SJavier Martinez Canillas mutex_lock(&ts->input->mutex);
5164065d1e7SJavier Martinez Canillas
517d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(ts->input))
5184065d1e7SJavier Martinez Canillas cyttsp_enable(ts);
5194065d1e7SJavier Martinez Canillas
5204065d1e7SJavier Martinez Canillas ts->suspended = false;
5214065d1e7SJavier Martinez Canillas
5224065d1e7SJavier Martinez Canillas mutex_unlock(&ts->input->mutex);
5234065d1e7SJavier Martinez Canillas
5244065d1e7SJavier Martinez Canillas return 0;
5254065d1e7SJavier Martinez Canillas }
5264065d1e7SJavier Martinez Canillas
527c3c2f2bcSJonathan Cameron EXPORT_GPL_SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
5284065d1e7SJavier Martinez Canillas
cyttsp_open(struct input_dev * dev)5294065d1e7SJavier Martinez Canillas static int cyttsp_open(struct input_dev *dev)
5304065d1e7SJavier Martinez Canillas {
5314065d1e7SJavier Martinez Canillas struct cyttsp *ts = input_get_drvdata(dev);
5324065d1e7SJavier Martinez Canillas int retval = 0;
5334065d1e7SJavier Martinez Canillas
5344065d1e7SJavier Martinez Canillas if (!ts->suspended)
5354065d1e7SJavier Martinez Canillas retval = cyttsp_enable(ts);
5364065d1e7SJavier Martinez Canillas
5374065d1e7SJavier Martinez Canillas return retval;
5384065d1e7SJavier Martinez Canillas }
5394065d1e7SJavier Martinez Canillas
cyttsp_close(struct input_dev * dev)5404065d1e7SJavier Martinez Canillas static void cyttsp_close(struct input_dev *dev)
5414065d1e7SJavier Martinez Canillas {
5424065d1e7SJavier Martinez Canillas struct cyttsp *ts = input_get_drvdata(dev);
5434065d1e7SJavier Martinez Canillas
5444065d1e7SJavier Martinez Canillas if (!ts->suspended)
5454065d1e7SJavier Martinez Canillas cyttsp_disable(ts);
5464065d1e7SJavier Martinez Canillas }
5474065d1e7SJavier Martinez Canillas
cyttsp_parse_properties(struct cyttsp * ts)548707b61bbSOreste Salerno static int cyttsp_parse_properties(struct cyttsp *ts)
549e4cf92baSOreste Salerno {
550707b61bbSOreste Salerno struct device *dev = ts->dev;
551707b61bbSOreste Salerno u32 dt_value;
552707b61bbSOreste Salerno int ret;
553e4cf92baSOreste Salerno
554707b61bbSOreste Salerno ts->bl_keys = devm_kzalloc(dev, CY_NUM_BL_KEYS, GFP_KERNEL);
555707b61bbSOreste Salerno if (!ts->bl_keys)
556707b61bbSOreste Salerno return -ENOMEM;
557707b61bbSOreste Salerno
558707b61bbSOreste Salerno /* Set some default values */
559707b61bbSOreste Salerno ts->use_hndshk = false;
560707b61bbSOreste Salerno ts->act_dist = CY_ACT_DIST_DFLT;
561707b61bbSOreste Salerno ts->act_intrvl = CY_ACT_INTRVL_DFLT;
562707b61bbSOreste Salerno ts->tch_tmout = CY_TCH_TMOUT_DFLT;
563707b61bbSOreste Salerno ts->lp_intrvl = CY_LP_INTRVL_DFLT;
564707b61bbSOreste Salerno
565707b61bbSOreste Salerno ret = device_property_read_u8_array(dev, "bootloader-key",
566707b61bbSOreste Salerno ts->bl_keys, CY_NUM_BL_KEYS);
567707b61bbSOreste Salerno if (ret) {
568707b61bbSOreste Salerno dev_err(dev,
569707b61bbSOreste Salerno "bootloader-key property could not be retrieved\n");
570707b61bbSOreste Salerno return ret;
571707b61bbSOreste Salerno }
572707b61bbSOreste Salerno
573707b61bbSOreste Salerno ts->use_hndshk = device_property_present(dev, "use-handshake");
574707b61bbSOreste Salerno
575707b61bbSOreste Salerno if (!device_property_read_u32(dev, "active-distance", &dt_value)) {
576707b61bbSOreste Salerno if (dt_value > 15) {
577707b61bbSOreste Salerno dev_err(dev, "active-distance (%u) must be [0-15]\n",
578707b61bbSOreste Salerno dt_value);
579707b61bbSOreste Salerno return -EINVAL;
580707b61bbSOreste Salerno }
581707b61bbSOreste Salerno ts->act_dist &= ~CY_ACT_DIST_MASK;
582707b61bbSOreste Salerno ts->act_dist |= dt_value;
583707b61bbSOreste Salerno }
584707b61bbSOreste Salerno
585707b61bbSOreste Salerno if (!device_property_read_u32(dev, "active-interval-ms", &dt_value)) {
586707b61bbSOreste Salerno if (dt_value > 255) {
587707b61bbSOreste Salerno dev_err(dev, "active-interval-ms (%u) must be [0-255]\n",
588707b61bbSOreste Salerno dt_value);
589707b61bbSOreste Salerno return -EINVAL;
590707b61bbSOreste Salerno }
591707b61bbSOreste Salerno ts->act_intrvl = dt_value;
592707b61bbSOreste Salerno }
593707b61bbSOreste Salerno
594707b61bbSOreste Salerno if (!device_property_read_u32(dev, "lowpower-interval-ms", &dt_value)) {
595707b61bbSOreste Salerno if (dt_value > 2550) {
596707b61bbSOreste Salerno dev_err(dev, "lowpower-interval-ms (%u) must be [0-2550]\n",
597707b61bbSOreste Salerno dt_value);
598707b61bbSOreste Salerno return -EINVAL;
599707b61bbSOreste Salerno }
600707b61bbSOreste Salerno /* Register value is expressed in 0.01s / bit */
601707b61bbSOreste Salerno ts->lp_intrvl = dt_value / 10;
602707b61bbSOreste Salerno }
603707b61bbSOreste Salerno
604707b61bbSOreste Salerno if (!device_property_read_u32(dev, "touch-timeout-ms", &dt_value)) {
605707b61bbSOreste Salerno if (dt_value > 2550) {
606707b61bbSOreste Salerno dev_err(dev, "touch-timeout-ms (%u) must be [0-2550]\n",
607707b61bbSOreste Salerno dt_value);
608707b61bbSOreste Salerno return -EINVAL;
609707b61bbSOreste Salerno }
610707b61bbSOreste Salerno /* Register value is expressed in 0.01s / bit */
611707b61bbSOreste Salerno ts->tch_tmout = dt_value / 10;
612707b61bbSOreste Salerno }
613707b61bbSOreste Salerno
614707b61bbSOreste Salerno return 0;
615e4cf92baSOreste Salerno }
616e4cf92baSOreste Salerno
cyttsp_probe(const struct cyttsp_bus_ops * bus_ops,struct device * dev,int irq,size_t xfer_buf_size)6174065d1e7SJavier Martinez Canillas struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
6184065d1e7SJavier Martinez Canillas struct device *dev, int irq, size_t xfer_buf_size)
6194065d1e7SJavier Martinez Canillas {
620*ae25dbacSDmitry Torokhov /*
621*ae25dbacSDmitry Torokhov * VCPIN is the analog voltage supply
622*ae25dbacSDmitry Torokhov * VDD is the digital voltage supply
623*ae25dbacSDmitry Torokhov */
624*ae25dbacSDmitry Torokhov static const char * const supplies[] = { "vcpin", "vdd" };
6254065d1e7SJavier Martinez Canillas struct cyttsp *ts;
6264065d1e7SJavier Martinez Canillas struct input_dev *input_dev;
6274065d1e7SJavier Martinez Canillas int error;
6284065d1e7SJavier Martinez Canillas
629e4cf92baSOreste Salerno ts = devm_kzalloc(dev, sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
630e4cf92baSOreste Salerno if (!ts)
631e4cf92baSOreste Salerno return ERR_PTR(-ENOMEM);
632e4cf92baSOreste Salerno
633e4cf92baSOreste Salerno input_dev = devm_input_allocate_device(dev);
634e4cf92baSOreste Salerno if (!input_dev)
635e4cf92baSOreste Salerno return ERR_PTR(-ENOMEM);
6364065d1e7SJavier Martinez Canillas
6374065d1e7SJavier Martinez Canillas ts->dev = dev;
6384065d1e7SJavier Martinez Canillas ts->input = input_dev;
6394065d1e7SJavier Martinez Canillas ts->bus_ops = bus_ops;
6404065d1e7SJavier Martinez Canillas ts->irq = irq;
6414065d1e7SJavier Martinez Canillas
642*ae25dbacSDmitry Torokhov error = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies),
643*ae25dbacSDmitry Torokhov supplies);
6446cf3b3abSLinus Walleij if (error) {
645*ae25dbacSDmitry Torokhov dev_err(dev, "Failed to enable regulators: %d\n", error);
6466cf3b3abSLinus Walleij return ERR_PTR(error);
6476cf3b3abSLinus Walleij }
6486cf3b3abSLinus Walleij
649707b61bbSOreste Salerno ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
650707b61bbSOreste Salerno if (IS_ERR(ts->reset_gpio)) {
651707b61bbSOreste Salerno error = PTR_ERR(ts->reset_gpio);
652707b61bbSOreste Salerno dev_err(dev, "Failed to request reset gpio, error %d\n", error);
653707b61bbSOreste Salerno return ERR_PTR(error);
654707b61bbSOreste Salerno }
655707b61bbSOreste Salerno
656707b61bbSOreste Salerno error = cyttsp_parse_properties(ts);
657707b61bbSOreste Salerno if (error)
658707b61bbSOreste Salerno return ERR_PTR(error);
659707b61bbSOreste Salerno
6604065d1e7SJavier Martinez Canillas init_completion(&ts->bl_ready);
6614065d1e7SJavier Martinez Canillas
662707b61bbSOreste Salerno input_dev->name = "Cypress TTSP TouchScreen";
6634065d1e7SJavier Martinez Canillas input_dev->id.bustype = bus_ops->bustype;
6644065d1e7SJavier Martinez Canillas input_dev->dev.parent = ts->dev;
6654065d1e7SJavier Martinez Canillas
6664065d1e7SJavier Martinez Canillas input_dev->open = cyttsp_open;
6674065d1e7SJavier Martinez Canillas input_dev->close = cyttsp_close;
6684065d1e7SJavier Martinez Canillas
6694065d1e7SJavier Martinez Canillas input_set_drvdata(input_dev, ts);
6704065d1e7SJavier Martinez Canillas
671707b61bbSOreste Salerno input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
672707b61bbSOreste Salerno input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
673ddfe7e1cSLinus Walleij /* One byte for width 0..255 so this is the limit */
674ddfe7e1cSLinus Walleij input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
675ddfe7e1cSLinus Walleij
676ed7c9870SHans de Goede touchscreen_parse_properties(input_dev, true, NULL);
6774065d1e7SJavier Martinez Canillas
678dadf1fd8SLinus Walleij error = input_mt_init_slots(input_dev, CY_MAX_ID, INPUT_MT_DIRECT);
67969a12402SOreste Salerno if (error) {
68069a12402SOreste Salerno dev_err(dev, "Unable to init MT slots.\n");
68169a12402SOreste Salerno return ERR_PTR(error);
68269a12402SOreste Salerno }
6834065d1e7SJavier Martinez Canillas
684e4cf92baSOreste Salerno error = devm_request_threaded_irq(dev, ts->irq, NULL, cyttsp_irq,
685c9d2939dSDmitry Torokhov IRQF_ONESHOT | IRQF_NO_AUTOEN,
686707b61bbSOreste Salerno "cyttsp", ts);
6874065d1e7SJavier Martinez Canillas if (error) {
6884065d1e7SJavier Martinez Canillas dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
6894065d1e7SJavier Martinez Canillas ts->irq, error);
690e4cf92baSOreste Salerno return ERR_PTR(error);
6914065d1e7SJavier Martinez Canillas }
6924065d1e7SJavier Martinez Canillas
6938fb81d20SOreste Salerno cyttsp_hard_reset(ts);
6948fb81d20SOreste Salerno
6954065d1e7SJavier Martinez Canillas error = cyttsp_power_on(ts);
6964065d1e7SJavier Martinez Canillas if (error)
697e4cf92baSOreste Salerno return ERR_PTR(error);
6984065d1e7SJavier Martinez Canillas
6994065d1e7SJavier Martinez Canillas error = input_register_device(input_dev);
7004065d1e7SJavier Martinez Canillas if (error) {
7014065d1e7SJavier Martinez Canillas dev_err(ts->dev, "failed to register input device: %d\n",
7024065d1e7SJavier Martinez Canillas error);
703e4cf92baSOreste Salerno return ERR_PTR(error);
7044065d1e7SJavier Martinez Canillas }
7054065d1e7SJavier Martinez Canillas
7064065d1e7SJavier Martinez Canillas return ts;
7074065d1e7SJavier Martinez Canillas }
7084065d1e7SJavier Martinez Canillas EXPORT_SYMBOL_GPL(cyttsp_probe);
7094065d1e7SJavier Martinez Canillas
7104065d1e7SJavier Martinez Canillas MODULE_LICENSE("GPL");
7114065d1e7SJavier Martinez Canillas MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
7124065d1e7SJavier Martinez Canillas MODULE_AUTHOR("Cypress");
713