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/gpio.h> 214065d1e7SJavier Martinez Canillas #include <linux/interrupt.h> 224065d1e7SJavier Martinez Canillas #include <linux/slab.h> 23707b61bbSOreste Salerno #include <linux/property.h> 24707b61bbSOreste Salerno #include <linux/gpio/consumer.h> 256cf3b3abSLinus Walleij #include <linux/regulator/consumer.h> 264065d1e7SJavier Martinez Canillas 274065d1e7SJavier Martinez Canillas #include "cyttsp_core.h" 284065d1e7SJavier Martinez Canillas 294065d1e7SJavier Martinez Canillas /* Bootloader number of command keys */ 304065d1e7SJavier Martinez Canillas #define CY_NUM_BL_KEYS 8 314065d1e7SJavier Martinez Canillas 324065d1e7SJavier Martinez Canillas /* helpers */ 334065d1e7SJavier Martinez Canillas #define GET_NUM_TOUCHES(x) ((x) & 0x0F) 344065d1e7SJavier Martinez Canillas #define IS_LARGE_AREA(x) (((x) & 0x10) >> 4) 354065d1e7SJavier Martinez Canillas #define IS_BAD_PKT(x) ((x) & 0x20) 364065d1e7SJavier Martinez Canillas #define IS_VALID_APP(x) ((x) & 0x01) 374065d1e7SJavier Martinez Canillas #define IS_OPERATIONAL_ERR(x) ((x) & 0x3F) 384065d1e7SJavier Martinez Canillas #define GET_HSTMODE(reg) (((reg) & 0x70) >> 4) 394065d1e7SJavier Martinez Canillas #define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4) 404065d1e7SJavier Martinez Canillas 414065d1e7SJavier Martinez Canillas #define CY_REG_BASE 0x00 424065d1e7SJavier Martinez Canillas #define CY_REG_ACT_DIST 0x1E 434065d1e7SJavier Martinez Canillas #define CY_REG_ACT_INTRVL 0x1D 444065d1e7SJavier Martinez Canillas #define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1) 454065d1e7SJavier Martinez Canillas #define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1) 464065d1e7SJavier Martinez Canillas #define CY_MAXZ 255 474065d1e7SJavier Martinez Canillas #define CY_DELAY_DFLT 20 /* ms */ 484065d1e7SJavier Martinez Canillas #define CY_DELAY_MAX 500 49*d27ac0fbSDmitry Torokhov /* Active distance in pixels for a gesture to be reported */ 50*d27ac0fbSDmitry Torokhov #define CY_ACT_DIST_DFLT 0xF8 /* pixels */ 51707b61bbSOreste Salerno #define CY_ACT_DIST_MASK 0x0F 52*d27ac0fbSDmitry Torokhov /* Active Power state scanning/processing refresh interval */ 53*d27ac0fbSDmitry Torokhov #define CY_ACT_INTRVL_DFLT 0x00 /* ms */ 54*d27ac0fbSDmitry Torokhov /* Low Power state scanning/processing refresh interval */ 55*d27ac0fbSDmitry Torokhov #define CY_LP_INTRVL_DFLT 0x0A /* ms */ 56*d27ac0fbSDmitry Torokhov /* touch timeout for the Active power */ 57*d27ac0fbSDmitry Torokhov #define CY_TCH_TMOUT_DFLT 0xFF /* ms */ 584065d1e7SJavier Martinez Canillas #define CY_HNDSHK_BIT 0x80 594065d1e7SJavier Martinez Canillas /* device mode bits */ 604065d1e7SJavier Martinez Canillas #define CY_OPERATE_MODE 0x00 614065d1e7SJavier Martinez Canillas #define CY_SYSINFO_MODE 0x10 624065d1e7SJavier Martinez Canillas /* power mode select bits */ 634065d1e7SJavier Martinez Canillas #define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */ 644065d1e7SJavier Martinez Canillas #define CY_DEEP_SLEEP_MODE 0x02 654065d1e7SJavier Martinez Canillas #define CY_LOW_POWER_MODE 0x04 664065d1e7SJavier Martinez Canillas 674065d1e7SJavier Martinez Canillas /* Slots management */ 684065d1e7SJavier Martinez Canillas #define CY_MAX_FINGER 4 694065d1e7SJavier Martinez Canillas #define CY_MAX_ID 16 704065d1e7SJavier Martinez Canillas 714065d1e7SJavier Martinez Canillas static const u8 bl_command[] = { 724065d1e7SJavier Martinez Canillas 0x00, /* file offset */ 734065d1e7SJavier Martinez Canillas 0xFF, /* command */ 744065d1e7SJavier Martinez Canillas 0xA5, /* exit bootloader command */ 754065d1e7SJavier Martinez Canillas 0, 1, 2, 3, 4, 5, 6, 7 /* default keys */ 764065d1e7SJavier Martinez Canillas }; 774065d1e7SJavier Martinez Canillas 784065d1e7SJavier Martinez Canillas static int ttsp_read_block_data(struct cyttsp *ts, u8 command, 794065d1e7SJavier Martinez Canillas u8 length, void *buf) 804065d1e7SJavier Martinez Canillas { 814065d1e7SJavier Martinez Canillas int error; 824065d1e7SJavier Martinez Canillas int tries; 834065d1e7SJavier Martinez Canillas 844065d1e7SJavier Martinez Canillas for (tries = 0; tries < CY_NUM_RETRY; tries++) { 859664877eSFerruh Yigit error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command, 869664877eSFerruh Yigit length, buf); 874065d1e7SJavier Martinez Canillas if (!error) 884065d1e7SJavier Martinez Canillas return 0; 894065d1e7SJavier Martinez Canillas 904065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT); 914065d1e7SJavier Martinez Canillas } 924065d1e7SJavier Martinez Canillas 934065d1e7SJavier Martinez Canillas return -EIO; 944065d1e7SJavier Martinez Canillas } 954065d1e7SJavier Martinez Canillas 964065d1e7SJavier Martinez Canillas static int ttsp_write_block_data(struct cyttsp *ts, u8 command, 974065d1e7SJavier Martinez Canillas u8 length, void *buf) 984065d1e7SJavier Martinez Canillas { 994065d1e7SJavier Martinez Canillas int error; 1004065d1e7SJavier Martinez Canillas int tries; 1014065d1e7SJavier Martinez Canillas 1024065d1e7SJavier Martinez Canillas for (tries = 0; tries < CY_NUM_RETRY; tries++) { 1039664877eSFerruh Yigit error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command, 1049664877eSFerruh Yigit length, buf); 1054065d1e7SJavier Martinez Canillas if (!error) 1064065d1e7SJavier Martinez Canillas return 0; 1074065d1e7SJavier Martinez Canillas 1084065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT); 1094065d1e7SJavier Martinez Canillas } 1104065d1e7SJavier Martinez Canillas 1114065d1e7SJavier Martinez Canillas return -EIO; 1124065d1e7SJavier Martinez Canillas } 1134065d1e7SJavier Martinez Canillas 1144065d1e7SJavier Martinez Canillas static int ttsp_send_command(struct cyttsp *ts, u8 cmd) 1154065d1e7SJavier Martinez Canillas { 1164065d1e7SJavier Martinez Canillas return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd); 1174065d1e7SJavier Martinez Canillas } 1184065d1e7SJavier Martinez Canillas 119fbd5e77eSFerruh Yigit static int cyttsp_handshake(struct cyttsp *ts) 120fbd5e77eSFerruh Yigit { 121707b61bbSOreste Salerno if (ts->use_hndshk) 122fbd5e77eSFerruh Yigit return ttsp_send_command(ts, 123fbd5e77eSFerruh Yigit ts->xy_data.hst_mode ^ CY_HNDSHK_BIT); 124fbd5e77eSFerruh Yigit 125fbd5e77eSFerruh Yigit return 0; 126fbd5e77eSFerruh Yigit } 127fbd5e77eSFerruh Yigit 1284065d1e7SJavier Martinez Canillas static int cyttsp_load_bl_regs(struct cyttsp *ts) 1294065d1e7SJavier Martinez Canillas { 1304065d1e7SJavier Martinez Canillas memset(&ts->bl_data, 0, sizeof(ts->bl_data)); 1314065d1e7SJavier Martinez Canillas ts->bl_data.bl_status = 0x10; 1324065d1e7SJavier Martinez Canillas 1334065d1e7SJavier Martinez Canillas return ttsp_read_block_data(ts, CY_REG_BASE, 1344065d1e7SJavier Martinez Canillas sizeof(ts->bl_data), &ts->bl_data); 1354065d1e7SJavier Martinez Canillas } 1364065d1e7SJavier Martinez Canillas 1374065d1e7SJavier Martinez Canillas static int cyttsp_exit_bl_mode(struct cyttsp *ts) 1384065d1e7SJavier Martinez Canillas { 1394065d1e7SJavier Martinez Canillas int error; 1404065d1e7SJavier Martinez Canillas u8 bl_cmd[sizeof(bl_command)]; 1414065d1e7SJavier Martinez Canillas 1424065d1e7SJavier Martinez Canillas memcpy(bl_cmd, bl_command, sizeof(bl_command)); 143707b61bbSOreste Salerno if (ts->bl_keys) 1444065d1e7SJavier Martinez Canillas memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS], 145707b61bbSOreste Salerno ts->bl_keys, CY_NUM_BL_KEYS); 1464065d1e7SJavier Martinez Canillas 1474065d1e7SJavier Martinez Canillas error = ttsp_write_block_data(ts, CY_REG_BASE, 1484065d1e7SJavier Martinez Canillas sizeof(bl_cmd), bl_cmd); 1494065d1e7SJavier Martinez Canillas if (error) 1504065d1e7SJavier Martinez Canillas return error; 1514065d1e7SJavier Martinez Canillas 1524065d1e7SJavier Martinez Canillas /* wait for TTSP Device to complete the operation */ 1534065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT); 1544065d1e7SJavier Martinez Canillas 1554065d1e7SJavier Martinez Canillas error = cyttsp_load_bl_regs(ts); 1564065d1e7SJavier Martinez Canillas if (error) 1574065d1e7SJavier Martinez Canillas return error; 1584065d1e7SJavier Martinez Canillas 1594065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) 1604065d1e7SJavier Martinez Canillas return -EIO; 1614065d1e7SJavier Martinez Canillas 1624065d1e7SJavier Martinez Canillas return 0; 1634065d1e7SJavier Martinez Canillas } 1644065d1e7SJavier Martinez Canillas 1654065d1e7SJavier Martinez Canillas static int cyttsp_set_operational_mode(struct cyttsp *ts) 1664065d1e7SJavier Martinez Canillas { 1674065d1e7SJavier Martinez Canillas int error; 1684065d1e7SJavier Martinez Canillas 1694065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_OPERATE_MODE); 1704065d1e7SJavier Martinez Canillas if (error) 1714065d1e7SJavier Martinez Canillas return error; 1724065d1e7SJavier Martinez Canillas 1734065d1e7SJavier Martinez Canillas /* wait for TTSP Device to complete switch to Operational mode */ 1744065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE, 1754065d1e7SJavier Martinez Canillas sizeof(ts->xy_data), &ts->xy_data); 1764065d1e7SJavier Martinez Canillas if (error) 1774065d1e7SJavier Martinez Canillas return error; 1784065d1e7SJavier Martinez Canillas 179fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts); 180fbd5e77eSFerruh Yigit if (error) 181fbd5e77eSFerruh Yigit return error; 182fbd5e77eSFerruh Yigit 1834065d1e7SJavier Martinez Canillas return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0; 1844065d1e7SJavier Martinez Canillas } 1854065d1e7SJavier Martinez Canillas 1864065d1e7SJavier Martinez Canillas static int cyttsp_set_sysinfo_mode(struct cyttsp *ts) 1874065d1e7SJavier Martinez Canillas { 1884065d1e7SJavier Martinez Canillas int error; 1894065d1e7SJavier Martinez Canillas 1904065d1e7SJavier Martinez Canillas memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data)); 1914065d1e7SJavier Martinez Canillas 1924065d1e7SJavier Martinez Canillas /* switch to sysinfo mode */ 1934065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_SYSINFO_MODE); 1944065d1e7SJavier Martinez Canillas if (error) 1954065d1e7SJavier Martinez Canillas return error; 1964065d1e7SJavier Martinez Canillas 1974065d1e7SJavier Martinez Canillas /* read sysinfo registers */ 1984065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT); 1994065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data), 2004065d1e7SJavier Martinez Canillas &ts->sysinfo_data); 2014065d1e7SJavier Martinez Canillas if (error) 2024065d1e7SJavier Martinez Canillas return error; 2034065d1e7SJavier Martinez Canillas 204fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts); 205fbd5e77eSFerruh Yigit if (error) 206fbd5e77eSFerruh Yigit return error; 207fbd5e77eSFerruh Yigit 2084065d1e7SJavier Martinez Canillas if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl) 2094065d1e7SJavier Martinez Canillas return -EIO; 2104065d1e7SJavier Martinez Canillas 2114065d1e7SJavier Martinez Canillas return 0; 2124065d1e7SJavier Martinez Canillas } 2134065d1e7SJavier Martinez Canillas 2144065d1e7SJavier Martinez Canillas static int cyttsp_set_sysinfo_regs(struct cyttsp *ts) 2154065d1e7SJavier Martinez Canillas { 2164065d1e7SJavier Martinez Canillas int retval = 0; 2174065d1e7SJavier Martinez Canillas 218707b61bbSOreste Salerno if (ts->act_intrvl != CY_ACT_INTRVL_DFLT || 219707b61bbSOreste Salerno ts->tch_tmout != CY_TCH_TMOUT_DFLT || 220707b61bbSOreste Salerno ts->lp_intrvl != CY_LP_INTRVL_DFLT) { 2214065d1e7SJavier Martinez Canillas 2224065d1e7SJavier Martinez Canillas u8 intrvl_ray[] = { 223707b61bbSOreste Salerno ts->act_intrvl, 224707b61bbSOreste Salerno ts->tch_tmout, 225707b61bbSOreste Salerno ts->lp_intrvl 2264065d1e7SJavier Martinez Canillas }; 2274065d1e7SJavier Martinez Canillas 2284065d1e7SJavier Martinez Canillas /* set intrvl registers */ 2294065d1e7SJavier Martinez Canillas retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL, 2304065d1e7SJavier Martinez Canillas sizeof(intrvl_ray), intrvl_ray); 2314065d1e7SJavier Martinez Canillas msleep(CY_DELAY_DFLT); 2324065d1e7SJavier Martinez Canillas } 2334065d1e7SJavier Martinez Canillas 2344065d1e7SJavier Martinez Canillas return retval; 2354065d1e7SJavier Martinez Canillas } 2364065d1e7SJavier Martinez Canillas 2378fb81d20SOreste Salerno static void cyttsp_hard_reset(struct cyttsp *ts) 2388fb81d20SOreste Salerno { 2398fb81d20SOreste Salerno if (ts->reset_gpio) { 240c61ac36fSLinus Walleij /* 241c61ac36fSLinus Walleij * According to the CY8CTMA340 datasheet page 21, the external 242c61ac36fSLinus Walleij * reset pulse width should be >= 1 ms. The datasheet does not 243c61ac36fSLinus Walleij * specify how long we have to wait after reset but a vendor 244c61ac36fSLinus Walleij * tree specifies 5 ms here. 245c61ac36fSLinus Walleij */ 2468fb81d20SOreste Salerno gpiod_set_value_cansleep(ts->reset_gpio, 1); 247c61ac36fSLinus Walleij usleep_range(1000, 2000); 2488fb81d20SOreste Salerno gpiod_set_value_cansleep(ts->reset_gpio, 0); 249c61ac36fSLinus Walleij usleep_range(5000, 6000); 2508fb81d20SOreste Salerno } 2518fb81d20SOreste Salerno } 2528fb81d20SOreste Salerno 2534065d1e7SJavier Martinez Canillas static int cyttsp_soft_reset(struct cyttsp *ts) 2544065d1e7SJavier Martinez Canillas { 2554065d1e7SJavier Martinez Canillas int retval; 2564065d1e7SJavier Martinez Canillas 2574065d1e7SJavier Martinez Canillas /* wait for interrupt to set ready completion */ 25816735d02SWolfram Sang reinit_completion(&ts->bl_ready); 2594065d1e7SJavier Martinez Canillas ts->state = CY_BL_STATE; 2604065d1e7SJavier Martinez Canillas 2614065d1e7SJavier Martinez Canillas enable_irq(ts->irq); 2624065d1e7SJavier Martinez Canillas 2634065d1e7SJavier Martinez Canillas retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE); 26484c36ab7SLinus Walleij if (retval) { 26584c36ab7SLinus Walleij dev_err(ts->dev, "failed to send soft reset\n"); 2664065d1e7SJavier Martinez Canillas goto out; 26784c36ab7SLinus Walleij } 2684065d1e7SJavier Martinez Canillas 26984c36ab7SLinus Walleij if (!wait_for_completion_timeout(&ts->bl_ready, 27084c36ab7SLinus Walleij msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX))) { 27184c36ab7SLinus Walleij dev_err(ts->dev, "timeout waiting for soft reset\n"); 27284c36ab7SLinus Walleij retval = -EIO; 27384c36ab7SLinus Walleij } 2744065d1e7SJavier Martinez Canillas 2754065d1e7SJavier Martinez Canillas out: 2764065d1e7SJavier Martinez Canillas ts->state = CY_IDLE_STATE; 2774065d1e7SJavier Martinez Canillas disable_irq(ts->irq); 2784065d1e7SJavier Martinez Canillas return retval; 2794065d1e7SJavier Martinez Canillas } 2804065d1e7SJavier Martinez Canillas 2814065d1e7SJavier Martinez Canillas static int cyttsp_act_dist_setup(struct cyttsp *ts) 2824065d1e7SJavier Martinez Canillas { 283707b61bbSOreste Salerno u8 act_dist_setup = ts->act_dist; 2844065d1e7SJavier Martinez Canillas 2854065d1e7SJavier Martinez Canillas /* Init gesture; active distance setup */ 2864065d1e7SJavier Martinez Canillas return ttsp_write_block_data(ts, CY_REG_ACT_DIST, 2874065d1e7SJavier Martinez Canillas sizeof(act_dist_setup), &act_dist_setup); 2884065d1e7SJavier Martinez Canillas } 2894065d1e7SJavier Martinez Canillas 2904065d1e7SJavier Martinez Canillas static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids) 2914065d1e7SJavier Martinez Canillas { 2924065d1e7SJavier Martinez Canillas ids[0] = xy_data->touch12_id >> 4; 2934065d1e7SJavier Martinez Canillas ids[1] = xy_data->touch12_id & 0xF; 2944065d1e7SJavier Martinez Canillas ids[2] = xy_data->touch34_id >> 4; 2954065d1e7SJavier Martinez Canillas ids[3] = xy_data->touch34_id & 0xF; 2964065d1e7SJavier Martinez Canillas } 2974065d1e7SJavier Martinez Canillas 2984065d1e7SJavier Martinez Canillas static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data, 2994065d1e7SJavier Martinez Canillas int idx) 3004065d1e7SJavier Martinez Canillas { 3014065d1e7SJavier Martinez Canillas switch (idx) { 3024065d1e7SJavier Martinez Canillas case 0: 3034065d1e7SJavier Martinez Canillas return &xy_data->tch1; 3044065d1e7SJavier Martinez Canillas case 1: 3054065d1e7SJavier Martinez Canillas return &xy_data->tch2; 3064065d1e7SJavier Martinez Canillas case 2: 3074065d1e7SJavier Martinez Canillas return &xy_data->tch3; 3084065d1e7SJavier Martinez Canillas case 3: 3094065d1e7SJavier Martinez Canillas return &xy_data->tch4; 3104065d1e7SJavier Martinez Canillas default: 3114065d1e7SJavier Martinez Canillas return NULL; 3124065d1e7SJavier Martinez Canillas } 3134065d1e7SJavier Martinez Canillas } 3144065d1e7SJavier Martinez Canillas 3154065d1e7SJavier Martinez Canillas static void cyttsp_report_tchdata(struct cyttsp *ts) 3164065d1e7SJavier Martinez Canillas { 3174065d1e7SJavier Martinez Canillas struct cyttsp_xydata *xy_data = &ts->xy_data; 3184065d1e7SJavier Martinez Canillas struct input_dev *input = ts->input; 3194065d1e7SJavier Martinez Canillas int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat); 3204065d1e7SJavier Martinez Canillas const struct cyttsp_tch *tch; 3214065d1e7SJavier Martinez Canillas int ids[CY_MAX_ID]; 3224065d1e7SJavier Martinez Canillas int i; 3234065d1e7SJavier Martinez Canillas DECLARE_BITMAP(used, CY_MAX_ID); 3244065d1e7SJavier Martinez Canillas 3254065d1e7SJavier Martinez Canillas if (IS_LARGE_AREA(xy_data->tt_stat) == 1) { 3264065d1e7SJavier Martinez Canillas /* terminate all active tracks */ 3274065d1e7SJavier Martinez Canillas num_tch = 0; 3284065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Large area detected\n", __func__); 3294065d1e7SJavier Martinez Canillas } else if (num_tch > CY_MAX_FINGER) { 3304065d1e7SJavier Martinez Canillas /* terminate all active tracks */ 3314065d1e7SJavier Martinez Canillas num_tch = 0; 3324065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__); 3334065d1e7SJavier Martinez Canillas } else if (IS_BAD_PKT(xy_data->tt_mode)) { 3344065d1e7SJavier Martinez Canillas /* terminate all active tracks */ 3354065d1e7SJavier Martinez Canillas num_tch = 0; 3364065d1e7SJavier Martinez Canillas dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__); 3374065d1e7SJavier Martinez Canillas } 3384065d1e7SJavier Martinez Canillas 3394065d1e7SJavier Martinez Canillas cyttsp_extract_track_ids(xy_data, ids); 3404065d1e7SJavier Martinez Canillas 3414065d1e7SJavier Martinez Canillas bitmap_zero(used, CY_MAX_ID); 3424065d1e7SJavier Martinez Canillas 3434065d1e7SJavier Martinez Canillas for (i = 0; i < num_tch; i++) { 3444065d1e7SJavier Martinez Canillas tch = cyttsp_get_tch(xy_data, i); 3454065d1e7SJavier Martinez Canillas 3464065d1e7SJavier Martinez Canillas input_mt_slot(input, ids[i]); 3474065d1e7SJavier Martinez Canillas input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 3484065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x)); 3494065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y)); 3504065d1e7SJavier Martinez Canillas input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z); 3514065d1e7SJavier Martinez Canillas 3524065d1e7SJavier Martinez Canillas __set_bit(ids[i], used); 3534065d1e7SJavier Martinez Canillas } 3544065d1e7SJavier Martinez Canillas 3554065d1e7SJavier Martinez Canillas for (i = 0; i < CY_MAX_ID; i++) { 3564065d1e7SJavier Martinez Canillas if (test_bit(i, used)) 3574065d1e7SJavier Martinez Canillas continue; 3584065d1e7SJavier Martinez Canillas 3594065d1e7SJavier Martinez Canillas input_mt_slot(input, i); 3605fc70e35SJiada Wang input_mt_report_slot_inactive(input); 3614065d1e7SJavier Martinez Canillas } 3624065d1e7SJavier Martinez Canillas 3634065d1e7SJavier Martinez Canillas input_sync(input); 3644065d1e7SJavier Martinez Canillas } 3654065d1e7SJavier Martinez Canillas 3664065d1e7SJavier Martinez Canillas static irqreturn_t cyttsp_irq(int irq, void *handle) 3674065d1e7SJavier Martinez Canillas { 3684065d1e7SJavier Martinez Canillas struct cyttsp *ts = handle; 3694065d1e7SJavier Martinez Canillas int error; 3704065d1e7SJavier Martinez Canillas 3714065d1e7SJavier Martinez Canillas if (unlikely(ts->state == CY_BL_STATE)) { 3724065d1e7SJavier Martinez Canillas complete(&ts->bl_ready); 3734065d1e7SJavier Martinez Canillas goto out; 3744065d1e7SJavier Martinez Canillas } 3754065d1e7SJavier Martinez Canillas 3764065d1e7SJavier Martinez Canillas /* Get touch data from CYTTSP device */ 3774065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE, 3784065d1e7SJavier Martinez Canillas sizeof(struct cyttsp_xydata), &ts->xy_data); 3794065d1e7SJavier Martinez Canillas if (error) 3804065d1e7SJavier Martinez Canillas goto out; 3814065d1e7SJavier Martinez Canillas 3824065d1e7SJavier Martinez Canillas /* provide flow control handshake */ 383fbd5e77eSFerruh Yigit error = cyttsp_handshake(ts); 3844065d1e7SJavier Martinez Canillas if (error) 3854065d1e7SJavier Martinez Canillas goto out; 3864065d1e7SJavier Martinez Canillas 3874065d1e7SJavier Martinez Canillas if (unlikely(ts->state == CY_IDLE_STATE)) 3884065d1e7SJavier Martinez Canillas goto out; 3894065d1e7SJavier Martinez Canillas 3904065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) { 3914065d1e7SJavier Martinez Canillas /* 3924065d1e7SJavier Martinez Canillas * TTSP device has reset back to bootloader mode. 3934065d1e7SJavier Martinez Canillas * Restore to operational mode. 3944065d1e7SJavier Martinez Canillas */ 3954065d1e7SJavier Martinez Canillas error = cyttsp_exit_bl_mode(ts); 3964065d1e7SJavier Martinez Canillas if (error) { 3974065d1e7SJavier Martinez Canillas dev_err(ts->dev, 3984065d1e7SJavier Martinez Canillas "Could not return to operational mode, err: %d\n", 3994065d1e7SJavier Martinez Canillas error); 4004065d1e7SJavier Martinez Canillas ts->state = CY_IDLE_STATE; 4014065d1e7SJavier Martinez Canillas } 4024065d1e7SJavier Martinez Canillas } else { 4034065d1e7SJavier Martinez Canillas cyttsp_report_tchdata(ts); 4044065d1e7SJavier Martinez Canillas } 4054065d1e7SJavier Martinez Canillas 4064065d1e7SJavier Martinez Canillas out: 4074065d1e7SJavier Martinez Canillas return IRQ_HANDLED; 4084065d1e7SJavier Martinez Canillas } 4094065d1e7SJavier Martinez Canillas 4104065d1e7SJavier Martinez Canillas static int cyttsp_power_on(struct cyttsp *ts) 4114065d1e7SJavier Martinez Canillas { 4124065d1e7SJavier Martinez Canillas int error; 4134065d1e7SJavier Martinez Canillas 4144065d1e7SJavier Martinez Canillas error = cyttsp_soft_reset(ts); 4154065d1e7SJavier Martinez Canillas if (error) 4164065d1e7SJavier Martinez Canillas return error; 4174065d1e7SJavier Martinez Canillas 4184065d1e7SJavier Martinez Canillas error = cyttsp_load_bl_regs(ts); 4194065d1e7SJavier Martinez Canillas if (error) 4204065d1e7SJavier Martinez Canillas return error; 4214065d1e7SJavier Martinez Canillas 4224065d1e7SJavier Martinez Canillas if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) && 4234065d1e7SJavier Martinez Canillas IS_VALID_APP(ts->bl_data.bl_status)) { 4244065d1e7SJavier Martinez Canillas error = cyttsp_exit_bl_mode(ts); 42539841136SLinus Walleij if (error) { 42639841136SLinus Walleij dev_err(ts->dev, "failed to exit bootloader mode\n"); 4274065d1e7SJavier Martinez Canillas return error; 4284065d1e7SJavier Martinez Canillas } 42939841136SLinus Walleij } 4304065d1e7SJavier Martinez Canillas 4314065d1e7SJavier Martinez Canillas if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE || 4324065d1e7SJavier Martinez Canillas IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) { 4334065d1e7SJavier Martinez Canillas return -ENODEV; 4344065d1e7SJavier Martinez Canillas } 4354065d1e7SJavier Martinez Canillas 4364065d1e7SJavier Martinez Canillas error = cyttsp_set_sysinfo_mode(ts); 4374065d1e7SJavier Martinez Canillas if (error) 4384065d1e7SJavier Martinez Canillas return error; 4394065d1e7SJavier Martinez Canillas 4404065d1e7SJavier Martinez Canillas error = cyttsp_set_sysinfo_regs(ts); 4414065d1e7SJavier Martinez Canillas if (error) 4424065d1e7SJavier Martinez Canillas return error; 4434065d1e7SJavier Martinez Canillas 4444065d1e7SJavier Martinez Canillas error = cyttsp_set_operational_mode(ts); 4454065d1e7SJavier Martinez Canillas if (error) 4464065d1e7SJavier Martinez Canillas return error; 4474065d1e7SJavier Martinez Canillas 4484065d1e7SJavier Martinez Canillas /* init active distance */ 4494065d1e7SJavier Martinez Canillas error = cyttsp_act_dist_setup(ts); 4504065d1e7SJavier Martinez Canillas if (error) 4514065d1e7SJavier Martinez Canillas return error; 4524065d1e7SJavier Martinez Canillas 4534065d1e7SJavier Martinez Canillas ts->state = CY_ACTIVE_STATE; 4544065d1e7SJavier Martinez Canillas 4554065d1e7SJavier Martinez Canillas return 0; 4564065d1e7SJavier Martinez Canillas } 4574065d1e7SJavier Martinez Canillas 4584065d1e7SJavier Martinez Canillas static int cyttsp_enable(struct cyttsp *ts) 4594065d1e7SJavier Martinez Canillas { 4604065d1e7SJavier Martinez Canillas int error; 4614065d1e7SJavier Martinez Canillas 4624065d1e7SJavier Martinez Canillas /* 4634065d1e7SJavier Martinez Canillas * The device firmware can wake on an I2C or SPI memory slave 4644065d1e7SJavier Martinez Canillas * address match. So just reading a register is sufficient to 4654065d1e7SJavier Martinez Canillas * wake up the device. The first read attempt will fail but it 4664065d1e7SJavier Martinez Canillas * will wake it up making the second read attempt successful. 4674065d1e7SJavier Martinez Canillas */ 4684065d1e7SJavier Martinez Canillas error = ttsp_read_block_data(ts, CY_REG_BASE, 4694065d1e7SJavier Martinez Canillas sizeof(ts->xy_data), &ts->xy_data); 4704065d1e7SJavier Martinez Canillas if (error) 4714065d1e7SJavier Martinez Canillas return error; 4724065d1e7SJavier Martinez Canillas 4734065d1e7SJavier Martinez Canillas if (GET_HSTMODE(ts->xy_data.hst_mode)) 4744065d1e7SJavier Martinez Canillas return -EIO; 4754065d1e7SJavier Martinez Canillas 4764065d1e7SJavier Martinez Canillas enable_irq(ts->irq); 4774065d1e7SJavier Martinez Canillas 4784065d1e7SJavier Martinez Canillas return 0; 4794065d1e7SJavier Martinez Canillas } 4804065d1e7SJavier Martinez Canillas 4814065d1e7SJavier Martinez Canillas static int cyttsp_disable(struct cyttsp *ts) 4824065d1e7SJavier Martinez Canillas { 4834065d1e7SJavier Martinez Canillas int error; 4844065d1e7SJavier Martinez Canillas 4854065d1e7SJavier Martinez Canillas error = ttsp_send_command(ts, CY_LOW_POWER_MODE); 4864065d1e7SJavier Martinez Canillas if (error) 4874065d1e7SJavier Martinez Canillas return error; 4884065d1e7SJavier Martinez Canillas 4894065d1e7SJavier Martinez Canillas disable_irq(ts->irq); 4904065d1e7SJavier Martinez Canillas 4914065d1e7SJavier Martinez Canillas return 0; 4924065d1e7SJavier Martinez Canillas } 4934065d1e7SJavier Martinez Canillas 49402b6a58bSJingoo Han static int __maybe_unused cyttsp_suspend(struct device *dev) 4954065d1e7SJavier Martinez Canillas { 4964065d1e7SJavier Martinez Canillas struct cyttsp *ts = dev_get_drvdata(dev); 4974065d1e7SJavier Martinez Canillas int retval = 0; 4984065d1e7SJavier Martinez Canillas 4994065d1e7SJavier Martinez Canillas mutex_lock(&ts->input->mutex); 5004065d1e7SJavier Martinez Canillas 501d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(ts->input)) { 5024065d1e7SJavier Martinez Canillas retval = cyttsp_disable(ts); 5034065d1e7SJavier Martinez Canillas if (retval == 0) 5044065d1e7SJavier Martinez Canillas ts->suspended = true; 5054065d1e7SJavier Martinez Canillas } 5064065d1e7SJavier Martinez Canillas 5074065d1e7SJavier Martinez Canillas mutex_unlock(&ts->input->mutex); 5084065d1e7SJavier Martinez Canillas 5094065d1e7SJavier Martinez Canillas return retval; 5104065d1e7SJavier Martinez Canillas } 5114065d1e7SJavier Martinez Canillas 51202b6a58bSJingoo Han static int __maybe_unused cyttsp_resume(struct device *dev) 5134065d1e7SJavier Martinez Canillas { 5144065d1e7SJavier Martinez Canillas struct cyttsp *ts = dev_get_drvdata(dev); 5154065d1e7SJavier Martinez Canillas 5164065d1e7SJavier Martinez Canillas mutex_lock(&ts->input->mutex); 5174065d1e7SJavier Martinez Canillas 518d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(ts->input)) 5194065d1e7SJavier Martinez Canillas cyttsp_enable(ts); 5204065d1e7SJavier Martinez Canillas 5214065d1e7SJavier Martinez Canillas ts->suspended = false; 5224065d1e7SJavier Martinez Canillas 5234065d1e7SJavier Martinez Canillas mutex_unlock(&ts->input->mutex); 5244065d1e7SJavier Martinez Canillas 5254065d1e7SJavier Martinez Canillas return 0; 5264065d1e7SJavier Martinez Canillas } 5274065d1e7SJavier Martinez Canillas 5284065d1e7SJavier Martinez Canillas SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume); 5294065d1e7SJavier Martinez Canillas EXPORT_SYMBOL_GPL(cyttsp_pm_ops); 5304065d1e7SJavier Martinez Canillas 5314065d1e7SJavier Martinez Canillas static int cyttsp_open(struct input_dev *dev) 5324065d1e7SJavier Martinez Canillas { 5334065d1e7SJavier Martinez Canillas struct cyttsp *ts = input_get_drvdata(dev); 5344065d1e7SJavier Martinez Canillas int retval = 0; 5354065d1e7SJavier Martinez Canillas 5364065d1e7SJavier Martinez Canillas if (!ts->suspended) 5374065d1e7SJavier Martinez Canillas retval = cyttsp_enable(ts); 5384065d1e7SJavier Martinez Canillas 5394065d1e7SJavier Martinez Canillas return retval; 5404065d1e7SJavier Martinez Canillas } 5414065d1e7SJavier Martinez Canillas 5424065d1e7SJavier Martinez Canillas static void cyttsp_close(struct input_dev *dev) 5434065d1e7SJavier Martinez Canillas { 5444065d1e7SJavier Martinez Canillas struct cyttsp *ts = input_get_drvdata(dev); 5454065d1e7SJavier Martinez Canillas 5464065d1e7SJavier Martinez Canillas if (!ts->suspended) 5474065d1e7SJavier Martinez Canillas cyttsp_disable(ts); 5484065d1e7SJavier Martinez Canillas } 5494065d1e7SJavier Martinez Canillas 550707b61bbSOreste Salerno static int cyttsp_parse_properties(struct cyttsp *ts) 551e4cf92baSOreste Salerno { 552707b61bbSOreste Salerno struct device *dev = ts->dev; 553707b61bbSOreste Salerno u32 dt_value; 554707b61bbSOreste Salerno int ret; 555e4cf92baSOreste Salerno 556707b61bbSOreste Salerno ts->bl_keys = devm_kzalloc(dev, CY_NUM_BL_KEYS, GFP_KERNEL); 557707b61bbSOreste Salerno if (!ts->bl_keys) 558707b61bbSOreste Salerno return -ENOMEM; 559707b61bbSOreste Salerno 560707b61bbSOreste Salerno /* Set some default values */ 561707b61bbSOreste Salerno ts->use_hndshk = false; 562707b61bbSOreste Salerno ts->act_dist = CY_ACT_DIST_DFLT; 563707b61bbSOreste Salerno ts->act_intrvl = CY_ACT_INTRVL_DFLT; 564707b61bbSOreste Salerno ts->tch_tmout = CY_TCH_TMOUT_DFLT; 565707b61bbSOreste Salerno ts->lp_intrvl = CY_LP_INTRVL_DFLT; 566707b61bbSOreste Salerno 567707b61bbSOreste Salerno ret = device_property_read_u8_array(dev, "bootloader-key", 568707b61bbSOreste Salerno ts->bl_keys, CY_NUM_BL_KEYS); 569707b61bbSOreste Salerno if (ret) { 570707b61bbSOreste Salerno dev_err(dev, 571707b61bbSOreste Salerno "bootloader-key property could not be retrieved\n"); 572707b61bbSOreste Salerno return ret; 573707b61bbSOreste Salerno } 574707b61bbSOreste Salerno 575707b61bbSOreste Salerno ts->use_hndshk = device_property_present(dev, "use-handshake"); 576707b61bbSOreste Salerno 577707b61bbSOreste Salerno if (!device_property_read_u32(dev, "active-distance", &dt_value)) { 578707b61bbSOreste Salerno if (dt_value > 15) { 579707b61bbSOreste Salerno dev_err(dev, "active-distance (%u) must be [0-15]\n", 580707b61bbSOreste Salerno dt_value); 581707b61bbSOreste Salerno return -EINVAL; 582707b61bbSOreste Salerno } 583707b61bbSOreste Salerno ts->act_dist &= ~CY_ACT_DIST_MASK; 584707b61bbSOreste Salerno ts->act_dist |= dt_value; 585707b61bbSOreste Salerno } 586707b61bbSOreste Salerno 587707b61bbSOreste Salerno if (!device_property_read_u32(dev, "active-interval-ms", &dt_value)) { 588707b61bbSOreste Salerno if (dt_value > 255) { 589707b61bbSOreste Salerno dev_err(dev, "active-interval-ms (%u) must be [0-255]\n", 590707b61bbSOreste Salerno dt_value); 591707b61bbSOreste Salerno return -EINVAL; 592707b61bbSOreste Salerno } 593707b61bbSOreste Salerno ts->act_intrvl = dt_value; 594707b61bbSOreste Salerno } 595707b61bbSOreste Salerno 596707b61bbSOreste Salerno if (!device_property_read_u32(dev, "lowpower-interval-ms", &dt_value)) { 597707b61bbSOreste Salerno if (dt_value > 2550) { 598707b61bbSOreste Salerno dev_err(dev, "lowpower-interval-ms (%u) must be [0-2550]\n", 599707b61bbSOreste Salerno dt_value); 600707b61bbSOreste Salerno return -EINVAL; 601707b61bbSOreste Salerno } 602707b61bbSOreste Salerno /* Register value is expressed in 0.01s / bit */ 603707b61bbSOreste Salerno ts->lp_intrvl = dt_value / 10; 604707b61bbSOreste Salerno } 605707b61bbSOreste Salerno 606707b61bbSOreste Salerno if (!device_property_read_u32(dev, "touch-timeout-ms", &dt_value)) { 607707b61bbSOreste Salerno if (dt_value > 2550) { 608707b61bbSOreste Salerno dev_err(dev, "touch-timeout-ms (%u) must be [0-2550]\n", 609707b61bbSOreste Salerno dt_value); 610707b61bbSOreste Salerno return -EINVAL; 611707b61bbSOreste Salerno } 612707b61bbSOreste Salerno /* Register value is expressed in 0.01s / bit */ 613707b61bbSOreste Salerno ts->tch_tmout = dt_value / 10; 614707b61bbSOreste Salerno } 615707b61bbSOreste Salerno 616707b61bbSOreste Salerno return 0; 617e4cf92baSOreste Salerno } 618e4cf92baSOreste Salerno 6196cf3b3abSLinus Walleij static void cyttsp_disable_regulators(void *_ts) 6206cf3b3abSLinus Walleij { 6216cf3b3abSLinus Walleij struct cyttsp *ts = _ts; 6226cf3b3abSLinus Walleij 6236cf3b3abSLinus Walleij regulator_bulk_disable(ARRAY_SIZE(ts->regulators), 6246cf3b3abSLinus Walleij ts->regulators); 6256cf3b3abSLinus Walleij } 6266cf3b3abSLinus Walleij 6274065d1e7SJavier Martinez Canillas struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, 6284065d1e7SJavier Martinez Canillas struct device *dev, int irq, size_t xfer_buf_size) 6294065d1e7SJavier Martinez Canillas { 6304065d1e7SJavier Martinez Canillas struct cyttsp *ts; 6314065d1e7SJavier Martinez Canillas struct input_dev *input_dev; 6324065d1e7SJavier Martinez Canillas int error; 6334065d1e7SJavier Martinez Canillas 634e4cf92baSOreste Salerno ts = devm_kzalloc(dev, sizeof(*ts) + xfer_buf_size, GFP_KERNEL); 635e4cf92baSOreste Salerno if (!ts) 636e4cf92baSOreste Salerno return ERR_PTR(-ENOMEM); 637e4cf92baSOreste Salerno 638e4cf92baSOreste Salerno input_dev = devm_input_allocate_device(dev); 639e4cf92baSOreste Salerno if (!input_dev) 640e4cf92baSOreste Salerno return ERR_PTR(-ENOMEM); 6414065d1e7SJavier Martinez Canillas 6424065d1e7SJavier Martinez Canillas ts->dev = dev; 6434065d1e7SJavier Martinez Canillas ts->input = input_dev; 6444065d1e7SJavier Martinez Canillas ts->bus_ops = bus_ops; 6454065d1e7SJavier Martinez Canillas ts->irq = irq; 6464065d1e7SJavier Martinez Canillas 6476cf3b3abSLinus Walleij /* 6486cf3b3abSLinus Walleij * VCPIN is the analog voltage supply 6496cf3b3abSLinus Walleij * VDD is the digital voltage supply 6506cf3b3abSLinus Walleij */ 6516cf3b3abSLinus Walleij ts->regulators[0].supply = "vcpin"; 6526cf3b3abSLinus Walleij ts->regulators[1].supply = "vdd"; 6536cf3b3abSLinus Walleij error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators), 6546cf3b3abSLinus Walleij ts->regulators); 6556cf3b3abSLinus Walleij if (error) { 6566cf3b3abSLinus Walleij dev_err(dev, "Failed to get regulators: %d\n", error); 6576cf3b3abSLinus Walleij return ERR_PTR(error); 6586cf3b3abSLinus Walleij } 6596cf3b3abSLinus Walleij 6606cf3b3abSLinus Walleij error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators), 6616cf3b3abSLinus Walleij ts->regulators); 6626cf3b3abSLinus Walleij if (error) { 6636cf3b3abSLinus Walleij dev_err(dev, "Cannot enable regulators: %d\n", error); 6646cf3b3abSLinus Walleij return ERR_PTR(error); 6656cf3b3abSLinus Walleij } 6666cf3b3abSLinus Walleij 6676cf3b3abSLinus Walleij error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts); 6686cf3b3abSLinus Walleij if (error) { 6696cf3b3abSLinus Walleij dev_err(dev, "failed to install chip disable handler\n"); 6706cf3b3abSLinus Walleij return ERR_PTR(error); 6716cf3b3abSLinus Walleij } 6726cf3b3abSLinus Walleij 673707b61bbSOreste Salerno ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 674707b61bbSOreste Salerno if (IS_ERR(ts->reset_gpio)) { 675707b61bbSOreste Salerno error = PTR_ERR(ts->reset_gpio); 676707b61bbSOreste Salerno dev_err(dev, "Failed to request reset gpio, error %d\n", error); 677707b61bbSOreste Salerno return ERR_PTR(error); 678707b61bbSOreste Salerno } 679707b61bbSOreste Salerno 680707b61bbSOreste Salerno error = cyttsp_parse_properties(ts); 681707b61bbSOreste Salerno if (error) 682707b61bbSOreste Salerno return ERR_PTR(error); 683707b61bbSOreste Salerno 6844065d1e7SJavier Martinez Canillas init_completion(&ts->bl_ready); 6854065d1e7SJavier Martinez Canillas 686707b61bbSOreste Salerno input_dev->name = "Cypress TTSP TouchScreen"; 6874065d1e7SJavier Martinez Canillas input_dev->id.bustype = bus_ops->bustype; 6884065d1e7SJavier Martinez Canillas input_dev->dev.parent = ts->dev; 6894065d1e7SJavier Martinez Canillas 6904065d1e7SJavier Martinez Canillas input_dev->open = cyttsp_open; 6914065d1e7SJavier Martinez Canillas input_dev->close = cyttsp_close; 6924065d1e7SJavier Martinez Canillas 6934065d1e7SJavier Martinez Canillas input_set_drvdata(input_dev, ts); 6944065d1e7SJavier Martinez Canillas 695707b61bbSOreste Salerno input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); 696707b61bbSOreste Salerno input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); 697ddfe7e1cSLinus Walleij /* One byte for width 0..255 so this is the limit */ 698ddfe7e1cSLinus Walleij input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 699ddfe7e1cSLinus Walleij 700ed7c9870SHans de Goede touchscreen_parse_properties(input_dev, true, NULL); 7014065d1e7SJavier Martinez Canillas 702dadf1fd8SLinus Walleij error = input_mt_init_slots(input_dev, CY_MAX_ID, INPUT_MT_DIRECT); 70369a12402SOreste Salerno if (error) { 70469a12402SOreste Salerno dev_err(dev, "Unable to init MT slots.\n"); 70569a12402SOreste Salerno return ERR_PTR(error); 70669a12402SOreste Salerno } 7074065d1e7SJavier Martinez Canillas 708e4cf92baSOreste Salerno error = devm_request_threaded_irq(dev, ts->irq, NULL, cyttsp_irq, 709c9d2939dSDmitry Torokhov IRQF_ONESHOT | IRQF_NO_AUTOEN, 710707b61bbSOreste Salerno "cyttsp", ts); 7114065d1e7SJavier Martinez Canillas if (error) { 7124065d1e7SJavier Martinez Canillas dev_err(ts->dev, "failed to request IRQ %d, err: %d\n", 7134065d1e7SJavier Martinez Canillas ts->irq, error); 714e4cf92baSOreste Salerno return ERR_PTR(error); 7154065d1e7SJavier Martinez Canillas } 7164065d1e7SJavier Martinez Canillas 7178fb81d20SOreste Salerno cyttsp_hard_reset(ts); 7188fb81d20SOreste Salerno 7194065d1e7SJavier Martinez Canillas error = cyttsp_power_on(ts); 7204065d1e7SJavier Martinez Canillas if (error) 721e4cf92baSOreste Salerno return ERR_PTR(error); 7224065d1e7SJavier Martinez Canillas 7234065d1e7SJavier Martinez Canillas error = input_register_device(input_dev); 7244065d1e7SJavier Martinez Canillas if (error) { 7254065d1e7SJavier Martinez Canillas dev_err(ts->dev, "failed to register input device: %d\n", 7264065d1e7SJavier Martinez Canillas error); 727e4cf92baSOreste Salerno return ERR_PTR(error); 7284065d1e7SJavier Martinez Canillas } 7294065d1e7SJavier Martinez Canillas 7304065d1e7SJavier Martinez Canillas return ts; 7314065d1e7SJavier Martinez Canillas } 7324065d1e7SJavier Martinez Canillas EXPORT_SYMBOL_GPL(cyttsp_probe); 7334065d1e7SJavier Martinez Canillas 7344065d1e7SJavier Martinez Canillas MODULE_LICENSE("GPL"); 7354065d1e7SJavier Martinez Canillas MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core"); 7364065d1e7SJavier Martinez Canillas MODULE_AUTHOR("Cypress"); 737