16d3a41abSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 243c4d13eSSimon Budig /* 343c4d13eSSimon Budig * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> 4fd335ab0SLothar Waßmann * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) 5dac90dc2SLothar Waßmann * Lothar Waßmann <LW@KARO-electronics.de> (DT support) 69dfd9708SDario Binacchi * Dario Binacchi <dario.binacchi@amarulasolutions.com> (regmap support) 743c4d13eSSimon Budig */ 843c4d13eSSimon Budig 943c4d13eSSimon Budig /* 1043c4d13eSSimon Budig * This is a driver for the EDT "Polytouch" family of touch controllers 1143c4d13eSSimon Budig * based on the FocalTech FT5x06 line of chips. 1243c4d13eSSimon Budig * 1343c4d13eSSimon Budig * Development of this driver has been sponsored by Glyn: 1443c4d13eSSimon Budig * http://www.glyn.com/Products/Displays 1543c4d13eSSimon Budig */ 1643c4d13eSSimon Budig 178726e4c9SMarco Felsch #include <linux/debugfs.h> 188726e4c9SMarco Felsch #include <linux/delay.h> 198726e4c9SMarco Felsch #include <linux/gpio/consumer.h> 208726e4c9SMarco Felsch #include <linux/i2c.h> 2143c4d13eSSimon Budig #include <linux/interrupt.h> 2243c4d13eSSimon Budig #include <linux/input.h> 2343c4d13eSSimon Budig #include <linux/input/mt.h> 242c005598SMaxime Ripard #include <linux/input/touchscreen.h> 258726e4c9SMarco Felsch #include <linux/irq.h> 268726e4c9SMarco Felsch #include <linux/kernel.h> 278726e4c9SMarco Felsch #include <linux/module.h> 285bcee83aSDario Binacchi #include <linux/property.h> 298726e4c9SMarco Felsch #include <linux/ratelimit.h> 309dfd9708SDario Binacchi #include <linux/regmap.h> 317448bfecSMylène Josserand #include <linux/regulator/consumer.h> 328726e4c9SMarco Felsch #include <linux/slab.h> 338726e4c9SMarco Felsch #include <linux/uaccess.h> 348726e4c9SMarco Felsch 358726e4c9SMarco Felsch #include <asm/unaligned.h> 3643c4d13eSSimon Budig 3743c4d13eSSimon Budig #define WORK_REGISTER_THRESHOLD 0x00 3843c4d13eSSimon Budig #define WORK_REGISTER_REPORT_RATE 0x08 3943c4d13eSSimon Budig #define WORK_REGISTER_GAIN 0x30 4043c4d13eSSimon Budig #define WORK_REGISTER_OFFSET 0x31 4143c4d13eSSimon Budig #define WORK_REGISTER_NUM_X 0x33 4243c4d13eSSimon Budig #define WORK_REGISTER_NUM_Y 0x34 4343c4d13eSSimon Budig 4421d1611aSMarco Felsch #define PMOD_REGISTER_ACTIVE 0x00 4521d1611aSMarco Felsch #define PMOD_REGISTER_HIBERNATE 0x03 4621d1611aSMarco Felsch 47fd335ab0SLothar Waßmann #define M09_REGISTER_THRESHOLD 0x80 48fd335ab0SLothar Waßmann #define M09_REGISTER_GAIN 0x92 49fd335ab0SLothar Waßmann #define M09_REGISTER_OFFSET 0x93 50fd335ab0SLothar Waßmann #define M09_REGISTER_NUM_X 0x94 51fd335ab0SLothar Waßmann #define M09_REGISTER_NUM_Y 0x95 52fd335ab0SLothar Waßmann 5323ea98f4SDario Binacchi #define M12_REGISTER_REPORT_RATE 0x88 5423ea98f4SDario Binacchi 55a2f39dacSMarco Felsch #define EV_REGISTER_THRESHOLD 0x40 56a2f39dacSMarco Felsch #define EV_REGISTER_GAIN 0x41 57b6eba860SMarco Felsch #define EV_REGISTER_OFFSET_Y 0x45 58b6eba860SMarco Felsch #define EV_REGISTER_OFFSET_X 0x46 59a2f39dacSMarco Felsch 60fd335ab0SLothar Waßmann #define NO_REGISTER 0xff 61fd335ab0SLothar Waßmann 6243c4d13eSSimon Budig #define WORK_REGISTER_OPMODE 0x3c 6343c4d13eSSimon Budig #define FACTORY_REGISTER_OPMODE 0x01 6421d1611aSMarco Felsch #define PMOD_REGISTER_OPMODE 0xa5 6543c4d13eSSimon Budig 6643c4d13eSSimon Budig #define TOUCH_EVENT_DOWN 0x00 6743c4d13eSSimon Budig #define TOUCH_EVENT_UP 0x01 6843c4d13eSSimon Budig #define TOUCH_EVENT_ON 0x02 6943c4d13eSSimon Budig #define TOUCH_EVENT_RESERVED 0x03 7043c4d13eSSimon Budig 7143c4d13eSSimon Budig #define EDT_NAME_LEN 23 7243c4d13eSSimon Budig #define EDT_SWITCH_MODE_RETRIES 10 7343c4d13eSSimon Budig #define EDT_SWITCH_MODE_DELAY 5 /* msec */ 7443c4d13eSSimon Budig #define EDT_RAW_DATA_RETRIES 100 750eeecf60SAniroop Mathur #define EDT_RAW_DATA_DELAY 1000 /* usec */ 7643c4d13eSSimon Budig 7703161a95SDmitry Torokhov #define EDT_DEFAULT_NUM_X 1024 7803161a95SDmitry Torokhov #define EDT_DEFAULT_NUM_Y 1024 7903161a95SDmitry Torokhov 8065c67985SDario Binacchi #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) 8165c67985SDario Binacchi #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) 8265c67985SDario Binacchi 8321d1611aSMarco Felsch enum edt_pmode { 8421d1611aSMarco Felsch EDT_PMODE_NOT_SUPPORTED, 8521d1611aSMarco Felsch EDT_PMODE_HIBERNATE, 8621d1611aSMarco Felsch EDT_PMODE_POWEROFF, 8721d1611aSMarco Felsch }; 8821d1611aSMarco Felsch 89fd335ab0SLothar Waßmann enum edt_ver { 90169110c3SSimon Budig EDT_M06, 91169110c3SSimon Budig EDT_M09, 92aed5d0eeSSimon Budig EDT_M12, 93a2f39dacSMarco Felsch EV_FT, 94169110c3SSimon Budig GENERIC_FT, 95fd335ab0SLothar Waßmann }; 96fd335ab0SLothar Waßmann 97fd335ab0SLothar Waßmann struct edt_reg_addr { 98fd335ab0SLothar Waßmann int reg_threshold; 99fd335ab0SLothar Waßmann int reg_report_rate; 100fd335ab0SLothar Waßmann int reg_gain; 101fd335ab0SLothar Waßmann int reg_offset; 102b6eba860SMarco Felsch int reg_offset_x; 103b6eba860SMarco Felsch int reg_offset_y; 104fd335ab0SLothar Waßmann int reg_num_x; 105fd335ab0SLothar Waßmann int reg_num_y; 106fd335ab0SLothar Waßmann }; 107fd335ab0SLothar Waßmann 10843c4d13eSSimon Budig struct edt_ft5x06_ts_data { 10943c4d13eSSimon Budig struct i2c_client *client; 11043c4d13eSSimon Budig struct input_dev *input; 111ad368eb2SHans de Goede struct touchscreen_properties prop; 11243c4d13eSSimon Budig u16 num_x; 11343c4d13eSSimon Budig u16 num_y; 1147448bfecSMylène Josserand struct regulator *vcc; 115df4c40f4SStephan Gerhold struct regulator *iovcc; 11643c4d13eSSimon Budig 11713c23cd1SFranklin S Cooper Jr struct gpio_desc *reset_gpio; 11813c23cd1SFranklin S Cooper Jr struct gpio_desc *wake_gpio; 119dac90dc2SLothar Waßmann 1209dfd9708SDario Binacchi struct regmap *regmap; 1219dfd9708SDario Binacchi 12243c4d13eSSimon Budig #if defined(CONFIG_DEBUG_FS) 12343c4d13eSSimon Budig struct dentry *debug_dir; 12443c4d13eSSimon Budig u8 *raw_buffer; 12543c4d13eSSimon Budig size_t raw_bufsize; 12643c4d13eSSimon Budig #endif 12743c4d13eSSimon Budig 12843c4d13eSSimon Budig struct mutex mutex; 12943c4d13eSSimon Budig bool factory_mode; 13021d1611aSMarco Felsch enum edt_pmode suspend_mode; 13143c4d13eSSimon Budig int threshold; 13243c4d13eSSimon Budig int gain; 13343c4d13eSSimon Budig int offset; 134b6eba860SMarco Felsch int offset_x; 135b6eba860SMarco Felsch int offset_y; 13643c4d13eSSimon Budig int report_rate; 137b1d2a3ecSFranklin S Cooper Jr int max_support_points; 1380df28e71SDario Binacchi int point_len; 1390df28e71SDario Binacchi u8 tdata_cmd; 1400df28e71SDario Binacchi int tdata_len; 1410df28e71SDario Binacchi int tdata_offset; 14243c4d13eSSimon Budig 14343c4d13eSSimon Budig char name[EDT_NAME_LEN]; 144480343dcSDario Binacchi char fw_version[EDT_NAME_LEN]; 145fd335ab0SLothar Waßmann 146fd335ab0SLothar Waßmann struct edt_reg_addr reg_addr; 147fd335ab0SLothar Waßmann enum edt_ver version; 148b777f93bSDario Binacchi unsigned int crc_errors; 149b777f93bSDario Binacchi unsigned int header_errors; 15043c4d13eSSimon Budig }; 15143c4d13eSSimon Budig 152b1d2a3ecSFranklin S Cooper Jr struct edt_i2c_chip_data { 153b1d2a3ecSFranklin S Cooper Jr int max_support_points; 154b1d2a3ecSFranklin S Cooper Jr }; 155b1d2a3ecSFranklin S Cooper Jr 1569dfd9708SDario Binacchi static const struct regmap_config edt_ft5x06_i2c_regmap_config = { 1579dfd9708SDario Binacchi .reg_bits = 8, 1589dfd9708SDario Binacchi .val_bits = 8, 1599dfd9708SDario Binacchi }; 16043c4d13eSSimon Budig 16143c4d13eSSimon Budig static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, 16243c4d13eSSimon Budig u8 *buf, int buflen) 16343c4d13eSSimon Budig { 16443c4d13eSSimon Budig int i; 16543c4d13eSSimon Budig u8 crc = 0; 16643c4d13eSSimon Budig 16743c4d13eSSimon Budig for (i = 0; i < buflen - 1; i++) 16843c4d13eSSimon Budig crc ^= buf[i]; 16943c4d13eSSimon Budig 17043c4d13eSSimon Budig if (crc != buf[buflen - 1]) { 171b777f93bSDario Binacchi tsdata->crc_errors++; 17243c4d13eSSimon Budig dev_err_ratelimited(&tsdata->client->dev, 17343c4d13eSSimon Budig "crc error: 0x%02x expected, got 0x%02x\n", 17443c4d13eSSimon Budig crc, buf[buflen - 1]); 17543c4d13eSSimon Budig return false; 17643c4d13eSSimon Budig } 17743c4d13eSSimon Budig 17843c4d13eSSimon Budig return true; 17943c4d13eSSimon Budig } 18043c4d13eSSimon Budig 1819dfd9708SDario Binacchi static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, 1829dfd9708SDario Binacchi void *val_buf, size_t val_size) 1839dfd9708SDario Binacchi { 1849dfd9708SDario Binacchi struct device *dev = context; 1859dfd9708SDario Binacchi struct i2c_client *i2c = to_i2c_client(dev); 1869dfd9708SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); 1879dfd9708SDario Binacchi struct i2c_msg xfer[2]; 1889dfd9708SDario Binacchi bool reg_read = false; 1899dfd9708SDario Binacchi u8 addr; 1909dfd9708SDario Binacchi u8 wlen; 1919dfd9708SDario Binacchi u8 wbuf[4], rbuf[3]; 1929dfd9708SDario Binacchi int ret; 1939dfd9708SDario Binacchi 1949dfd9708SDario Binacchi addr = *((u8 *)reg_buf); 1959dfd9708SDario Binacchi wbuf[0] = addr; 1969dfd9708SDario Binacchi switch (addr) { 1979dfd9708SDario Binacchi case 0xf5: 1989dfd9708SDario Binacchi wlen = 3; 1999dfd9708SDario Binacchi wbuf[0] = 0xf5; 2009dfd9708SDario Binacchi wbuf[1] = 0xe; 2019dfd9708SDario Binacchi wbuf[2] = *((u8 *)val_buf); 2029dfd9708SDario Binacchi break; 2039dfd9708SDario Binacchi case 0xf9: 2049dfd9708SDario Binacchi wlen = 1; 2059dfd9708SDario Binacchi break; 2069dfd9708SDario Binacchi default: 2079dfd9708SDario Binacchi wlen = 2; 2089dfd9708SDario Binacchi reg_read = true; 2099dfd9708SDario Binacchi wbuf[0] = M06_REG_CMD(tsdata->factory_mode); 2109dfd9708SDario Binacchi wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); 2119dfd9708SDario Binacchi wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; 2129dfd9708SDario Binacchi } 2139dfd9708SDario Binacchi 2149dfd9708SDario Binacchi xfer[0].addr = i2c->addr; 2159dfd9708SDario Binacchi xfer[0].flags = 0; 2169dfd9708SDario Binacchi xfer[0].len = wlen; 2179dfd9708SDario Binacchi xfer[0].buf = wbuf; 2189dfd9708SDario Binacchi 2199dfd9708SDario Binacchi xfer[1].addr = i2c->addr; 2209dfd9708SDario Binacchi xfer[1].flags = I2C_M_RD; 2219dfd9708SDario Binacchi xfer[1].len = reg_read ? 2 : val_size; 2229dfd9708SDario Binacchi xfer[1].buf = reg_read ? rbuf : val_buf; 2239dfd9708SDario Binacchi 2249dfd9708SDario Binacchi ret = i2c_transfer(i2c->adapter, xfer, 2); 2259dfd9708SDario Binacchi if (ret != 2) { 2269dfd9708SDario Binacchi if (ret < 0) 2279dfd9708SDario Binacchi return ret; 2289dfd9708SDario Binacchi 2299dfd9708SDario Binacchi return -EIO; 2309dfd9708SDario Binacchi } 2319dfd9708SDario Binacchi 2329dfd9708SDario Binacchi if (addr == 0xf9) { 2339dfd9708SDario Binacchi u8 *buf = (u8 *)val_buf; 2349dfd9708SDario Binacchi 2359dfd9708SDario Binacchi if (buf[0] != 0xaa || buf[1] != 0xaa || 2369dfd9708SDario Binacchi buf[2] != val_size) { 2379dfd9708SDario Binacchi tsdata->header_errors++; 2389dfd9708SDario Binacchi dev_err_ratelimited(dev, 2399dfd9708SDario Binacchi "Unexpected header: %02x%02x%02x\n", 2409dfd9708SDario Binacchi buf[0], buf[1], buf[2]); 2419dfd9708SDario Binacchi return -EIO; 2429dfd9708SDario Binacchi } 2439dfd9708SDario Binacchi 2449dfd9708SDario Binacchi if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size)) 2459dfd9708SDario Binacchi return -EIO; 2469dfd9708SDario Binacchi } else if (reg_read) { 247079e60a5SDario Binacchi wbuf[2] = rbuf[0]; 248079e60a5SDario Binacchi wbuf[3] = rbuf[1]; 249079e60a5SDario Binacchi if (!edt_ft5x06_ts_check_crc(tsdata, wbuf, 4)) 2509dfd9708SDario Binacchi return -EIO; 2519dfd9708SDario Binacchi 2529dfd9708SDario Binacchi *((u8 *)val_buf) = rbuf[0]; 2539dfd9708SDario Binacchi } 2549dfd9708SDario Binacchi 2559dfd9708SDario Binacchi return 0; 2569dfd9708SDario Binacchi } 2579dfd9708SDario Binacchi 2589dfd9708SDario Binacchi static int edt_M06_i2c_write(void *context, const void *data, size_t count) 2599dfd9708SDario Binacchi { 2609dfd9708SDario Binacchi struct device *dev = context; 2619dfd9708SDario Binacchi struct i2c_client *i2c = to_i2c_client(dev); 2629dfd9708SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); 2639dfd9708SDario Binacchi u8 addr, val; 2649dfd9708SDario Binacchi u8 wbuf[4]; 2659dfd9708SDario Binacchi struct i2c_msg xfer; 2669dfd9708SDario Binacchi int ret; 2679dfd9708SDario Binacchi 2689dfd9708SDario Binacchi addr = *((u8 *)data); 2699dfd9708SDario Binacchi val = *((u8 *)data + 1); 2709dfd9708SDario Binacchi 2719dfd9708SDario Binacchi wbuf[0] = M06_REG_CMD(tsdata->factory_mode); 2729dfd9708SDario Binacchi wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); 2739dfd9708SDario Binacchi wbuf[2] = val; 2749dfd9708SDario Binacchi wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2]; 2759dfd9708SDario Binacchi 2769dfd9708SDario Binacchi xfer.addr = i2c->addr; 2779dfd9708SDario Binacchi xfer.flags = 0; 2789dfd9708SDario Binacchi xfer.len = 4; 2799dfd9708SDario Binacchi xfer.buf = wbuf; 2809dfd9708SDario Binacchi 2819dfd9708SDario Binacchi ret = i2c_transfer(i2c->adapter, &xfer, 1); 2829dfd9708SDario Binacchi if (ret != 1) { 2839dfd9708SDario Binacchi if (ret < 0) 2849dfd9708SDario Binacchi return ret; 2859dfd9708SDario Binacchi 2869dfd9708SDario Binacchi return -EIO; 2879dfd9708SDario Binacchi } 2889dfd9708SDario Binacchi 2899dfd9708SDario Binacchi return 0; 2909dfd9708SDario Binacchi } 2919dfd9708SDario Binacchi 2929dfd9708SDario Binacchi static const struct regmap_config edt_M06_i2c_regmap_config = { 2939dfd9708SDario Binacchi .reg_bits = 8, 2949dfd9708SDario Binacchi .val_bits = 8, 2959dfd9708SDario Binacchi .read = edt_M06_i2c_read, 2969dfd9708SDario Binacchi .write = edt_M06_i2c_write, 2979dfd9708SDario Binacchi }; 2989dfd9708SDario Binacchi 29943c4d13eSSimon Budig static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) 30043c4d13eSSimon Budig { 30143c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = dev_id; 30243c4d13eSSimon Budig struct device *dev = &tsdata->client->dev; 3039378c025SFranklin S Cooper Jr u8 rdbuf[63]; 30443c4d13eSSimon Budig int i, type, x, y, id; 30543c4d13eSSimon Budig int error; 30643c4d13eSSimon Budig 30743c4d13eSSimon Budig memset(rdbuf, 0, sizeof(rdbuf)); 3080df28e71SDario Binacchi error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, 3090df28e71SDario Binacchi tsdata->tdata_len); 31043c4d13eSSimon Budig if (error) { 31143c4d13eSSimon Budig dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", 31243c4d13eSSimon Budig error); 31343c4d13eSSimon Budig goto out; 31443c4d13eSSimon Budig } 31543c4d13eSSimon Budig 316b1d2a3ecSFranklin S Cooper Jr for (i = 0; i < tsdata->max_support_points; i++) { 3170df28e71SDario Binacchi u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset]; 31843c4d13eSSimon Budig 31943c4d13eSSimon Budig type = buf[0] >> 6; 32043c4d13eSSimon Budig /* ignore Reserved events */ 32143c4d13eSSimon Budig if (type == TOUCH_EVENT_RESERVED) 32243c4d13eSSimon Budig continue; 32343c4d13eSSimon Budig 324fd335ab0SLothar Waßmann /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ 325169110c3SSimon Budig if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) 326ee3e946eSLothar Waßmann continue; 327ee3e946eSLothar Waßmann 3281b9c698cSDmitry Torokhov x = get_unaligned_be16(buf) & 0x0fff; 3291b9c698cSDmitry Torokhov y = get_unaligned_be16(buf + 2) & 0x0fff; 330a2f39dacSMarco Felsch /* The FT5x26 send the y coordinate first */ 331a2f39dacSMarco Felsch if (tsdata->version == EV_FT) 332a2f39dacSMarco Felsch swap(x, y); 333a2f39dacSMarco Felsch 33443c4d13eSSimon Budig id = (buf[2] >> 4) & 0x0f; 33543c4d13eSSimon Budig 33643c4d13eSSimon Budig input_mt_slot(tsdata->input, id); 33717b92927SDmitry Torokhov if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, 33817b92927SDmitry Torokhov type != TOUCH_EVENT_UP)) 33917b92927SDmitry Torokhov touchscreen_report_pos(tsdata->input, &tsdata->prop, 34017b92927SDmitry Torokhov x, y, true); 34143c4d13eSSimon Budig } 34243c4d13eSSimon Budig 34343c4d13eSSimon Budig input_mt_report_pointer_emulation(tsdata->input, true); 34443c4d13eSSimon Budig input_sync(tsdata->input); 34543c4d13eSSimon Budig 34643c4d13eSSimon Budig out: 34743c4d13eSSimon Budig return IRQ_HANDLED; 34843c4d13eSSimon Budig } 34943c4d13eSSimon Budig 35043c4d13eSSimon Budig struct edt_ft5x06_attribute { 35143c4d13eSSimon Budig struct device_attribute dattr; 35243c4d13eSSimon Budig size_t field_offset; 35343c4d13eSSimon Budig u8 limit_low; 35443c4d13eSSimon Budig u8 limit_high; 355fd335ab0SLothar Waßmann u8 addr_m06; 356fd335ab0SLothar Waßmann u8 addr_m09; 3572ebc1919SMarco Felsch u8 addr_ev; 35843c4d13eSSimon Budig }; 35943c4d13eSSimon Budig 3602ebc1919SMarco Felsch #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \ 361fd335ab0SLothar Waßmann _limit_low, _limit_high) \ 36243c4d13eSSimon Budig struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ 36343c4d13eSSimon Budig .dattr = __ATTR(_field, _mode, \ 36443c4d13eSSimon Budig edt_ft5x06_setting_show, \ 36543c4d13eSSimon Budig edt_ft5x06_setting_store), \ 366fd335ab0SLothar Waßmann .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ 367fd335ab0SLothar Waßmann .addr_m06 = _addr_m06, \ 368fd335ab0SLothar Waßmann .addr_m09 = _addr_m09, \ 3692ebc1919SMarco Felsch .addr_ev = _addr_ev, \ 37043c4d13eSSimon Budig .limit_low = _limit_low, \ 37143c4d13eSSimon Budig .limit_high = _limit_high, \ 37243c4d13eSSimon Budig } 37343c4d13eSSimon Budig 37443c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_show(struct device *dev, 37543c4d13eSSimon Budig struct device_attribute *dattr, 37643c4d13eSSimon Budig char *buf) 37743c4d13eSSimon Budig { 37843c4d13eSSimon Budig struct i2c_client *client = to_i2c_client(dev); 37943c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 38043c4d13eSSimon Budig struct edt_ft5x06_attribute *attr = 38143c4d13eSSimon Budig container_of(dattr, struct edt_ft5x06_attribute, dattr); 3821730d814SLothar Waßmann u8 *field = (u8 *)tsdata + attr->field_offset; 3839dfd9708SDario Binacchi unsigned int val; 38443c4d13eSSimon Budig size_t count = 0; 38543c4d13eSSimon Budig int error = 0; 386fd335ab0SLothar Waßmann u8 addr; 38743c4d13eSSimon Budig 38843c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 38943c4d13eSSimon Budig 39043c4d13eSSimon Budig if (tsdata->factory_mode) { 39143c4d13eSSimon Budig error = -EIO; 39243c4d13eSSimon Budig goto out; 39343c4d13eSSimon Budig } 39443c4d13eSSimon Budig 395fd335ab0SLothar Waßmann switch (tsdata->version) { 396169110c3SSimon Budig case EDT_M06: 397fd335ab0SLothar Waßmann addr = attr->addr_m06; 398fd335ab0SLothar Waßmann break; 399fd335ab0SLothar Waßmann 400169110c3SSimon Budig case EDT_M09: 401aed5d0eeSSimon Budig case EDT_M12: 402169110c3SSimon Budig case GENERIC_FT: 403fd335ab0SLothar Waßmann addr = attr->addr_m09; 404fd335ab0SLothar Waßmann break; 405fd335ab0SLothar Waßmann 4062ebc1919SMarco Felsch case EV_FT: 4072ebc1919SMarco Felsch addr = attr->addr_ev; 4082ebc1919SMarco Felsch break; 4092ebc1919SMarco Felsch 410fd335ab0SLothar Waßmann default: 411fd335ab0SLothar Waßmann error = -ENODEV; 412fd335ab0SLothar Waßmann goto out; 413fd335ab0SLothar Waßmann } 414fd335ab0SLothar Waßmann 415fd335ab0SLothar Waßmann if (addr != NO_REGISTER) { 4169dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, addr, &val); 4179dfd9708SDario Binacchi if (error) { 41843c4d13eSSimon Budig dev_err(&tsdata->client->dev, 41943c4d13eSSimon Budig "Failed to fetch attribute %s, error %d\n", 42043c4d13eSSimon Budig dattr->attr.name, error); 42143c4d13eSSimon Budig goto out; 42243c4d13eSSimon Budig } 423fd335ab0SLothar Waßmann } else { 424fd335ab0SLothar Waßmann val = *field; 425fd335ab0SLothar Waßmann } 42643c4d13eSSimon Budig 42743c4d13eSSimon Budig if (val != *field) { 42843c4d13eSSimon Budig dev_warn(&tsdata->client->dev, 42943c4d13eSSimon Budig "%s: read (%d) and stored value (%d) differ\n", 43043c4d13eSSimon Budig dattr->attr.name, val, *field); 43143c4d13eSSimon Budig *field = val; 43243c4d13eSSimon Budig } 43343c4d13eSSimon Budig 43443c4d13eSSimon Budig count = scnprintf(buf, PAGE_SIZE, "%d\n", val); 43543c4d13eSSimon Budig out: 43643c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 43743c4d13eSSimon Budig return error ?: count; 43843c4d13eSSimon Budig } 43943c4d13eSSimon Budig 44043c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_store(struct device *dev, 44143c4d13eSSimon Budig struct device_attribute *dattr, 44243c4d13eSSimon Budig const char *buf, size_t count) 44343c4d13eSSimon Budig { 44443c4d13eSSimon Budig struct i2c_client *client = to_i2c_client(dev); 44543c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 44643c4d13eSSimon Budig struct edt_ft5x06_attribute *attr = 44743c4d13eSSimon Budig container_of(dattr, struct edt_ft5x06_attribute, dattr); 4481730d814SLothar Waßmann u8 *field = (u8 *)tsdata + attr->field_offset; 44943c4d13eSSimon Budig unsigned int val; 45043c4d13eSSimon Budig int error; 451fd335ab0SLothar Waßmann u8 addr; 45243c4d13eSSimon Budig 45343c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 45443c4d13eSSimon Budig 45543c4d13eSSimon Budig if (tsdata->factory_mode) { 45643c4d13eSSimon Budig error = -EIO; 45743c4d13eSSimon Budig goto out; 45843c4d13eSSimon Budig } 45943c4d13eSSimon Budig 46043c4d13eSSimon Budig error = kstrtouint(buf, 0, &val); 46143c4d13eSSimon Budig if (error) 46243c4d13eSSimon Budig goto out; 46343c4d13eSSimon Budig 46443c4d13eSSimon Budig if (val < attr->limit_low || val > attr->limit_high) { 46543c4d13eSSimon Budig error = -ERANGE; 46643c4d13eSSimon Budig goto out; 46743c4d13eSSimon Budig } 46843c4d13eSSimon Budig 469fd335ab0SLothar Waßmann switch (tsdata->version) { 470169110c3SSimon Budig case EDT_M06: 471fd335ab0SLothar Waßmann addr = attr->addr_m06; 472fd335ab0SLothar Waßmann break; 473fd335ab0SLothar Waßmann 474169110c3SSimon Budig case EDT_M09: 475aed5d0eeSSimon Budig case EDT_M12: 476169110c3SSimon Budig case GENERIC_FT: 477fd335ab0SLothar Waßmann addr = attr->addr_m09; 478fd335ab0SLothar Waßmann break; 479fd335ab0SLothar Waßmann 4802ebc1919SMarco Felsch case EV_FT: 4812ebc1919SMarco Felsch addr = attr->addr_ev; 4822ebc1919SMarco Felsch break; 4832ebc1919SMarco Felsch 484fd335ab0SLothar Waßmann default: 485fd335ab0SLothar Waßmann error = -ENODEV; 486fd335ab0SLothar Waßmann goto out; 487fd335ab0SLothar Waßmann } 488fd335ab0SLothar Waßmann 489fd335ab0SLothar Waßmann if (addr != NO_REGISTER) { 4909dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, addr, val); 49143c4d13eSSimon Budig if (error) { 49243c4d13eSSimon Budig dev_err(&tsdata->client->dev, 49343c4d13eSSimon Budig "Failed to update attribute %s, error: %d\n", 49443c4d13eSSimon Budig dattr->attr.name, error); 49543c4d13eSSimon Budig goto out; 49643c4d13eSSimon Budig } 497fd335ab0SLothar Waßmann } 49843c4d13eSSimon Budig *field = val; 49943c4d13eSSimon Budig 50043c4d13eSSimon Budig out: 50143c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 50243c4d13eSSimon Budig return error ?: count; 50343c4d13eSSimon Budig } 50443c4d13eSSimon Budig 505aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-5 */ 506fd335ab0SLothar Waßmann static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 5072ebc1919SMarco Felsch M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31); 508aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-16 */ 509fd335ab0SLothar Waßmann static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 5102ebc1919SMarco Felsch M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); 511b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */ 512b6eba860SMarco Felsch static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, 513b6eba860SMarco Felsch EV_REGISTER_OFFSET_X, 0, 80); 514b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */ 515b6eba860SMarco Felsch static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, 516b6eba860SMarco Felsch EV_REGISTER_OFFSET_Y, 0, 80); 517aed5d0eeSSimon Budig /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ 518fd335ab0SLothar Waßmann static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, 5192ebc1919SMarco Felsch M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); 52023ea98f4SDario Binacchi /* m06: range 3 to 14, m12: range 1 to 255 */ 521fd335ab0SLothar Waßmann static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, 52223ea98f4SDario Binacchi M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255); 52343c4d13eSSimon Budig 52460790a58SDario Binacchi static ssize_t model_show(struct device *dev, struct device_attribute *attr, 52560790a58SDario Binacchi char *buf) 52660790a58SDario Binacchi { 52760790a58SDario Binacchi struct i2c_client *client = to_i2c_client(dev); 52860790a58SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 52960790a58SDario Binacchi 53060790a58SDario Binacchi return sysfs_emit(buf, "%s\n", tsdata->name); 53160790a58SDario Binacchi } 53260790a58SDario Binacchi 53360790a58SDario Binacchi static DEVICE_ATTR_RO(model); 53460790a58SDario Binacchi 535480343dcSDario Binacchi static ssize_t fw_version_show(struct device *dev, 536480343dcSDario Binacchi struct device_attribute *attr, char *buf) 537480343dcSDario Binacchi { 538480343dcSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 539480343dcSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 540480343dcSDario Binacchi 541480343dcSDario Binacchi return sysfs_emit(buf, "%s\n", tsdata->fw_version); 542480343dcSDario Binacchi } 543480343dcSDario Binacchi 544480343dcSDario Binacchi static DEVICE_ATTR_RO(fw_version); 545480343dcSDario Binacchi 546b777f93bSDario Binacchi /* m06 only */ 547b777f93bSDario Binacchi static ssize_t header_errors_show(struct device *dev, 548b777f93bSDario Binacchi struct device_attribute *attr, char *buf) 549b777f93bSDario Binacchi { 550b777f93bSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 551b777f93bSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 552b777f93bSDario Binacchi 553b777f93bSDario Binacchi return sysfs_emit(buf, "%d\n", tsdata->header_errors); 554b777f93bSDario Binacchi } 555b777f93bSDario Binacchi 556b777f93bSDario Binacchi static DEVICE_ATTR_RO(header_errors); 557b777f93bSDario Binacchi 558b777f93bSDario Binacchi /* m06 only */ 559b777f93bSDario Binacchi static ssize_t crc_errors_show(struct device *dev, 560b777f93bSDario Binacchi struct device_attribute *attr, char *buf) 561b777f93bSDario Binacchi { 562b777f93bSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 563b777f93bSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 564b777f93bSDario Binacchi 565b777f93bSDario Binacchi return sysfs_emit(buf, "%d\n", tsdata->crc_errors); 566b777f93bSDario Binacchi } 567b777f93bSDario Binacchi 568b777f93bSDario Binacchi static DEVICE_ATTR_RO(crc_errors); 569b777f93bSDario Binacchi 57043c4d13eSSimon Budig static struct attribute *edt_ft5x06_attrs[] = { 57143c4d13eSSimon Budig &edt_ft5x06_attr_gain.dattr.attr, 57243c4d13eSSimon Budig &edt_ft5x06_attr_offset.dattr.attr, 573b6eba860SMarco Felsch &edt_ft5x06_attr_offset_x.dattr.attr, 574b6eba860SMarco Felsch &edt_ft5x06_attr_offset_y.dattr.attr, 57543c4d13eSSimon Budig &edt_ft5x06_attr_threshold.dattr.attr, 57643c4d13eSSimon Budig &edt_ft5x06_attr_report_rate.dattr.attr, 57760790a58SDario Binacchi &dev_attr_model.attr, 578480343dcSDario Binacchi &dev_attr_fw_version.attr, 579b777f93bSDario Binacchi &dev_attr_header_errors.attr, 580b777f93bSDario Binacchi &dev_attr_crc_errors.attr, 58143c4d13eSSimon Budig NULL 58243c4d13eSSimon Budig }; 58343c4d13eSSimon Budig 58443c4d13eSSimon Budig static const struct attribute_group edt_ft5x06_attr_group = { 58543c4d13eSSimon Budig .attrs = edt_ft5x06_attrs, 58643c4d13eSSimon Budig }; 58743c4d13eSSimon Budig 588f4ee52f3SMarco Felsch static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) 589f4ee52f3SMarco Felsch { 590f4ee52f3SMarco Felsch struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 5919dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 592f4ee52f3SMarco Felsch 5939dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold); 5949dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_gain, tsdata->gain); 595f4ee52f3SMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 5969dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset, tsdata->offset); 597f4ee52f3SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 5989dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x); 599f4ee52f3SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 6009dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y); 601f4ee52f3SMarco Felsch if (reg_addr->reg_report_rate != NO_REGISTER) 6029dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_report_rate, 603f4ee52f3SMarco Felsch tsdata->report_rate); 604f4ee52f3SMarco Felsch } 605f4ee52f3SMarco Felsch 60643c4d13eSSimon Budig #ifdef CONFIG_DEBUG_FS 60743c4d13eSSimon Budig static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) 60843c4d13eSSimon Budig { 60943c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 61043c4d13eSSimon Budig int retries = EDT_SWITCH_MODE_RETRIES; 6119dfd9708SDario Binacchi unsigned int val; 61243c4d13eSSimon Budig int error; 61343c4d13eSSimon Budig 6144b3e910dSDmitry Torokhov if (tsdata->version != EDT_M06) { 6154b3e910dSDmitry Torokhov dev_err(&client->dev, 6164b3e910dSDmitry Torokhov "No factory mode support for non-M06 devices\n"); 6174b3e910dSDmitry Torokhov return -EINVAL; 6184b3e910dSDmitry Torokhov } 6194b3e910dSDmitry Torokhov 62043c4d13eSSimon Budig disable_irq(client->irq); 62143c4d13eSSimon Budig 62243c4d13eSSimon Budig if (!tsdata->raw_buffer) { 62343c4d13eSSimon Budig tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * 62443c4d13eSSimon Budig sizeof(u16); 62543c4d13eSSimon Budig tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL); 62643c4d13eSSimon Budig if (!tsdata->raw_buffer) { 62743c4d13eSSimon Budig error = -ENOMEM; 62843c4d13eSSimon Budig goto err_out; 62943c4d13eSSimon Budig } 63043c4d13eSSimon Budig } 63143c4d13eSSimon Budig 63243c4d13eSSimon Budig /* mode register is 0x3c when in the work mode */ 6339dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03); 63443c4d13eSSimon Budig if (error) { 63543c4d13eSSimon Budig dev_err(&client->dev, 63643c4d13eSSimon Budig "failed to switch to factory mode, error %d\n", error); 63743c4d13eSSimon Budig goto err_out; 63843c4d13eSSimon Budig } 63943c4d13eSSimon Budig 64043c4d13eSSimon Budig tsdata->factory_mode = true; 64143c4d13eSSimon Budig do { 64243c4d13eSSimon Budig mdelay(EDT_SWITCH_MODE_DELAY); 64343c4d13eSSimon Budig /* mode register is 0x01 when in factory mode */ 6449dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE, 6459dfd9708SDario Binacchi &val); 6469dfd9708SDario Binacchi if (!error && val == 0x03) 64743c4d13eSSimon Budig break; 64843c4d13eSSimon Budig } while (--retries > 0); 64943c4d13eSSimon Budig 65043c4d13eSSimon Budig if (retries == 0) { 65143c4d13eSSimon Budig dev_err(&client->dev, "not in factory mode after %dms.\n", 65243c4d13eSSimon Budig EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); 65343c4d13eSSimon Budig error = -EIO; 65443c4d13eSSimon Budig goto err_out; 65543c4d13eSSimon Budig } 65643c4d13eSSimon Budig 65743c4d13eSSimon Budig return 0; 65843c4d13eSSimon Budig 65943c4d13eSSimon Budig err_out: 66043c4d13eSSimon Budig kfree(tsdata->raw_buffer); 66143c4d13eSSimon Budig tsdata->raw_buffer = NULL; 66243c4d13eSSimon Budig tsdata->factory_mode = false; 66343c4d13eSSimon Budig enable_irq(client->irq); 66443c4d13eSSimon Budig 66543c4d13eSSimon Budig return error; 66643c4d13eSSimon Budig } 66743c4d13eSSimon Budig 66843c4d13eSSimon Budig static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) 66943c4d13eSSimon Budig { 67043c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 67143c4d13eSSimon Budig int retries = EDT_SWITCH_MODE_RETRIES; 6729dfd9708SDario Binacchi unsigned int val; 67343c4d13eSSimon Budig int error; 67443c4d13eSSimon Budig 67543c4d13eSSimon Budig /* mode register is 0x01 when in the factory mode */ 6769dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1); 67743c4d13eSSimon Budig if (error) { 67843c4d13eSSimon Budig dev_err(&client->dev, 67943c4d13eSSimon Budig "failed to switch to work mode, error: %d\n", error); 68043c4d13eSSimon Budig return error; 68143c4d13eSSimon Budig } 68243c4d13eSSimon Budig 68343c4d13eSSimon Budig tsdata->factory_mode = false; 68443c4d13eSSimon Budig 68543c4d13eSSimon Budig do { 68643c4d13eSSimon Budig mdelay(EDT_SWITCH_MODE_DELAY); 68743c4d13eSSimon Budig /* mode register is 0x01 when in factory mode */ 6889dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val); 6899dfd9708SDario Binacchi if (!error && val == 0x01) 69043c4d13eSSimon Budig break; 69143c4d13eSSimon Budig } while (--retries > 0); 69243c4d13eSSimon Budig 69343c4d13eSSimon Budig if (retries == 0) { 69443c4d13eSSimon Budig dev_err(&client->dev, "not in work mode after %dms.\n", 69543c4d13eSSimon Budig EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); 69643c4d13eSSimon Budig tsdata->factory_mode = true; 69743c4d13eSSimon Budig return -EIO; 69843c4d13eSSimon Budig } 69943c4d13eSSimon Budig 70043c4d13eSSimon Budig kfree(tsdata->raw_buffer); 70143c4d13eSSimon Budig tsdata->raw_buffer = NULL; 70243c4d13eSSimon Budig 703f4ee52f3SMarco Felsch edt_ft5x06_restore_reg_parameters(tsdata); 70443c4d13eSSimon Budig enable_irq(client->irq); 70543c4d13eSSimon Budig 70643c4d13eSSimon Budig return 0; 70743c4d13eSSimon Budig } 70843c4d13eSSimon Budig 70943c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode) 71043c4d13eSSimon Budig { 71143c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = data; 71243c4d13eSSimon Budig 71343c4d13eSSimon Budig *mode = tsdata->factory_mode; 71443c4d13eSSimon Budig 71543c4d13eSSimon Budig return 0; 71643c4d13eSSimon Budig }; 71743c4d13eSSimon Budig 71843c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) 71943c4d13eSSimon Budig { 72043c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = data; 72143c4d13eSSimon Budig int retval = 0; 72243c4d13eSSimon Budig 72343c4d13eSSimon Budig if (mode > 1) 72443c4d13eSSimon Budig return -ERANGE; 72543c4d13eSSimon Budig 72643c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 72743c4d13eSSimon Budig 72843c4d13eSSimon Budig if (mode != tsdata->factory_mode) { 72943c4d13eSSimon Budig retval = mode ? edt_ft5x06_factory_mode(tsdata) : 73043c4d13eSSimon Budig edt_ft5x06_work_mode(tsdata); 73143c4d13eSSimon Budig } 73243c4d13eSSimon Budig 73343c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 73443c4d13eSSimon Budig 73543c4d13eSSimon Budig return retval; 73643c4d13eSSimon Budig }; 73743c4d13eSSimon Budig 73843c4d13eSSimon Budig DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, 73943c4d13eSSimon Budig edt_ft5x06_debugfs_mode_set, "%llu\n"); 74043c4d13eSSimon Budig 74143c4d13eSSimon Budig static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, 742d19ec82cSDario Binacchi char __user *buf, size_t count, 743d19ec82cSDario Binacchi loff_t *off) 74443c4d13eSSimon Budig { 74543c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = file->private_data; 74643c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 74743c4d13eSSimon Budig int retries = EDT_RAW_DATA_RETRIES; 7489dfd9708SDario Binacchi unsigned int val; 7499dfd9708SDario Binacchi int i, error; 75043c4d13eSSimon Budig size_t read = 0; 75143c4d13eSSimon Budig int colbytes; 75243c4d13eSSimon Budig u8 *rdbuf; 75343c4d13eSSimon Budig 75443c4d13eSSimon Budig if (*off < 0 || *off >= tsdata->raw_bufsize) 75543c4d13eSSimon Budig return 0; 75643c4d13eSSimon Budig 75743c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 75843c4d13eSSimon Budig 75943c4d13eSSimon Budig if (!tsdata->factory_mode || !tsdata->raw_buffer) { 76043c4d13eSSimon Budig error = -EIO; 76143c4d13eSSimon Budig goto out; 76243c4d13eSSimon Budig } 76343c4d13eSSimon Budig 7649dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, 0x08, 0x01); 76543c4d13eSSimon Budig if (error) { 76624642661SDario Binacchi dev_err(&client->dev, 76743c4d13eSSimon Budig "failed to write 0x08 register, error %d\n", error); 76843c4d13eSSimon Budig goto out; 76943c4d13eSSimon Budig } 77043c4d13eSSimon Budig 77143c4d13eSSimon Budig do { 7720eeecf60SAniroop Mathur usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100); 7739dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, 0x08, &val); 7749dfd9708SDario Binacchi if (error) { 77524642661SDario Binacchi dev_err(&client->dev, 7769dfd9708SDario Binacchi "failed to read 0x08 register, error %d\n", 7779dfd9708SDario Binacchi error); 77843c4d13eSSimon Budig goto out; 77943c4d13eSSimon Budig } 78043c4d13eSSimon Budig 7819dfd9708SDario Binacchi if (val == 1) 7829dfd9708SDario Binacchi break; 7839dfd9708SDario Binacchi } while (--retries > 0); 7849dfd9708SDario Binacchi 78543c4d13eSSimon Budig if (retries == 0) { 78624642661SDario Binacchi dev_err(&client->dev, 78743c4d13eSSimon Budig "timed out waiting for register to settle\n"); 78843c4d13eSSimon Budig error = -ETIMEDOUT; 78943c4d13eSSimon Budig goto out; 79043c4d13eSSimon Budig } 79143c4d13eSSimon Budig 79243c4d13eSSimon Budig rdbuf = tsdata->raw_buffer; 79343c4d13eSSimon Budig colbytes = tsdata->num_y * sizeof(u16); 79443c4d13eSSimon Budig 79543c4d13eSSimon Budig for (i = 0; i < tsdata->num_x; i++) { 7969dfd9708SDario Binacchi rdbuf[0] = i; /* column index */ 7979dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes); 79843c4d13eSSimon Budig if (error) 79943c4d13eSSimon Budig goto out; 80043c4d13eSSimon Budig 80143c4d13eSSimon Budig rdbuf += colbytes; 80243c4d13eSSimon Budig } 80343c4d13eSSimon Budig 80443c4d13eSSimon Budig read = min_t(size_t, count, tsdata->raw_bufsize - *off); 80535b1da4eSAxel Lin if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { 80635b1da4eSAxel Lin error = -EFAULT; 80735b1da4eSAxel Lin goto out; 80835b1da4eSAxel Lin } 80935b1da4eSAxel Lin 81043c4d13eSSimon Budig *off += read; 81143c4d13eSSimon Budig out: 81243c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 81343c4d13eSSimon Budig return error ?: read; 81443c4d13eSSimon Budig }; 81543c4d13eSSimon Budig 81643c4d13eSSimon Budig static const struct file_operations debugfs_raw_data_fops = { 817f6c0df6aSWei Yongjun .open = simple_open, 81843c4d13eSSimon Budig .read = edt_ft5x06_debugfs_raw_data_read, 81943c4d13eSSimon Budig }; 82043c4d13eSSimon Budig 82121d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 82243c4d13eSSimon Budig const char *debugfs_name) 82343c4d13eSSimon Budig { 82443c4d13eSSimon Budig tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); 82543c4d13eSSimon Budig 82643c4d13eSSimon Budig debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); 82743c4d13eSSimon Budig debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); 82843c4d13eSSimon Budig 82943c4d13eSSimon Budig debugfs_create_file("mode", S_IRUSR | S_IWUSR, 83043c4d13eSSimon Budig tsdata->debug_dir, tsdata, &debugfs_mode_fops); 83143c4d13eSSimon Budig debugfs_create_file("raw_data", S_IRUSR, 83243c4d13eSSimon Budig tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); 83343c4d13eSSimon Budig } 83443c4d13eSSimon Budig 83521d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 83643c4d13eSSimon Budig { 83743c4d13eSSimon Budig debugfs_remove_recursive(tsdata->debug_dir); 838a1d0fa77SGuenter Roeck kfree(tsdata->raw_buffer); 83943c4d13eSSimon Budig } 84043c4d13eSSimon Budig 84143c4d13eSSimon Budig #else 84243c4d13eSSimon Budig 84321d1611aSMarco Felsch static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) 84421d1611aSMarco Felsch { 84521d1611aSMarco Felsch return -ENOSYS; 84621d1611aSMarco Felsch } 84721d1611aSMarco Felsch 84821d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 84943c4d13eSSimon Budig const char *debugfs_name) 85043c4d13eSSimon Budig { 85143c4d13eSSimon Budig } 85243c4d13eSSimon Budig 85321d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 85443c4d13eSSimon Budig { 85543c4d13eSSimon Budig } 85643c4d13eSSimon Budig 85743c4d13eSSimon Budig #endif /* CONFIG_DEBUGFS */ 85843c4d13eSSimon Budig 8595298cc4cSBill Pemberton static int edt_ft5x06_ts_identify(struct i2c_client *client, 860480343dcSDario Binacchi struct edt_ft5x06_ts_data *tsdata) 86143c4d13eSSimon Budig { 86243c4d13eSSimon Budig u8 rdbuf[EDT_NAME_LEN]; 86343c4d13eSSimon Budig char *p; 86443c4d13eSSimon Budig int error; 865fd335ab0SLothar Waßmann char *model_name = tsdata->name; 866480343dcSDario Binacchi char *fw_version = tsdata->fw_version; 86743c4d13eSSimon Budig 868fd335ab0SLothar Waßmann /* see what we find if we assume it is a M06 * 869fd335ab0SLothar Waßmann * if we get less than EDT_NAME_LEN, we don't want 870fd335ab0SLothar Waßmann * to have garbage in there 871fd335ab0SLothar Waßmann */ 872fd335ab0SLothar Waßmann memset(rdbuf, 0, sizeof(rdbuf)); 8739dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1); 87443c4d13eSSimon Budig if (error) 87543c4d13eSSimon Budig return error; 87643c4d13eSSimon Budig 877aed5d0eeSSimon Budig /* Probe content for something consistent. 878aed5d0eeSSimon Budig * M06 starts with a response byte, M12 gives the data directly. 879aed5d0eeSSimon Budig * M09/Generic does not provide model number information. 880fd335ab0SLothar Waßmann */ 881aed5d0eeSSimon Budig if (!strncasecmp(rdbuf + 1, "EP0", 3)) { 882169110c3SSimon Budig tsdata->version = EDT_M06; 883fd335ab0SLothar Waßmann 88443c4d13eSSimon Budig /* remove last '$' end marker */ 88543c4d13eSSimon Budig rdbuf[EDT_NAME_LEN - 1] = '\0'; 88643c4d13eSSimon Budig if (rdbuf[EDT_NAME_LEN - 2] == '$') 88743c4d13eSSimon Budig rdbuf[EDT_NAME_LEN - 2] = '\0'; 88843c4d13eSSimon Budig 88943c4d13eSSimon Budig /* look for Model/Version separator */ 89043c4d13eSSimon Budig p = strchr(rdbuf, '*'); 89143c4d13eSSimon Budig if (p) 89243c4d13eSSimon Budig *p++ = '\0'; 893a9f08ad7SWolfram Sang strscpy(model_name, rdbuf + 1, EDT_NAME_LEN); 894a9f08ad7SWolfram Sang strscpy(fw_version, p ? p : "", EDT_NAME_LEN); 8959dfd9708SDario Binacchi 8969dfd9708SDario Binacchi regmap_exit(tsdata->regmap); 8979dfd9708SDario Binacchi tsdata->regmap = regmap_init_i2c(client, 8989dfd9708SDario Binacchi &edt_M06_i2c_regmap_config); 8999dfd9708SDario Binacchi if (IS_ERR(tsdata->regmap)) { 9009dfd9708SDario Binacchi dev_err(&client->dev, "regmap allocation failed\n"); 9019dfd9708SDario Binacchi return PTR_ERR(tsdata->regmap); 9029dfd9708SDario Binacchi } 903aed5d0eeSSimon Budig } else if (!strncasecmp(rdbuf, "EP0", 3)) { 904aed5d0eeSSimon Budig tsdata->version = EDT_M12; 905aed5d0eeSSimon Budig 906aed5d0eeSSimon Budig /* remove last '$' end marker */ 907aed5d0eeSSimon Budig rdbuf[EDT_NAME_LEN - 2] = '\0'; 908aed5d0eeSSimon Budig if (rdbuf[EDT_NAME_LEN - 3] == '$') 909aed5d0eeSSimon Budig rdbuf[EDT_NAME_LEN - 3] = '\0'; 910aed5d0eeSSimon Budig 911aed5d0eeSSimon Budig /* look for Model/Version separator */ 912aed5d0eeSSimon Budig p = strchr(rdbuf, '*'); 913aed5d0eeSSimon Budig if (p) 914aed5d0eeSSimon Budig *p++ = '\0'; 915a9f08ad7SWolfram Sang strscpy(model_name, rdbuf, EDT_NAME_LEN); 916a9f08ad7SWolfram Sang strscpy(fw_version, p ? p : "", EDT_NAME_LEN); 917fd335ab0SLothar Waßmann } else { 918aed5d0eeSSimon Budig /* If it is not an EDT M06/M12 touchscreen, then the model 919169110c3SSimon Budig * detection is a bit hairy. The different ft5x06 92062c5e854SDario Binacchi * firmwares around don't reliably implement the 921169110c3SSimon Budig * identification registers. Well, we'll take a shot. 922169110c3SSimon Budig * 923169110c3SSimon Budig * The main difference between generic focaltec based 924169110c3SSimon Budig * touches and EDT M09 is that we know how to retrieve 925169110c3SSimon Budig * the max coordinates for the latter. 926169110c3SSimon Budig */ 927169110c3SSimon Budig tsdata->version = GENERIC_FT; 928fd335ab0SLothar Waßmann 9299dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2); 930fd335ab0SLothar Waßmann if (error) 931fd335ab0SLothar Waßmann return error; 932fd335ab0SLothar Waßmann 933a9f08ad7SWolfram Sang strscpy(fw_version, rdbuf, 2); 934fd335ab0SLothar Waßmann 9359dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1); 936fd335ab0SLothar Waßmann if (error) 937fd335ab0SLothar Waßmann return error; 938fd335ab0SLothar Waßmann 939169110c3SSimon Budig /* This "model identification" is not exact. Unfortunately 940169110c3SSimon Budig * not all firmwares for the ft5x06 put useful values in 941169110c3SSimon Budig * the identification registers. 942169110c3SSimon Budig */ 943169110c3SSimon Budig switch (rdbuf[0]) { 944146ea9b6SOliver Graute case 0x11: /* EDT EP0110M09 */ 945169110c3SSimon Budig case 0x35: /* EDT EP0350M09 */ 946169110c3SSimon Budig case 0x43: /* EDT EP0430M09 */ 947169110c3SSimon Budig case 0x50: /* EDT EP0500M09 */ 948169110c3SSimon Budig case 0x57: /* EDT EP0570M09 */ 949169110c3SSimon Budig case 0x70: /* EDT EP0700M09 */ 950169110c3SSimon Budig tsdata->version = EDT_M09; 951fd335ab0SLothar Waßmann snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", 952fd335ab0SLothar Waßmann rdbuf[0] >> 4, rdbuf[0] & 0x0F); 953169110c3SSimon Budig break; 954169110c3SSimon Budig case 0xa1: /* EDT EP1010ML00 */ 955169110c3SSimon Budig tsdata->version = EDT_M09; 956169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", 957169110c3SSimon Budig rdbuf[0] >> 4, rdbuf[0] & 0x0F); 958169110c3SSimon Budig break; 959169110c3SSimon Budig case 0x5a: /* Solomon Goldentek Display */ 960169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); 961169110c3SSimon Budig break; 962a2f39dacSMarco Felsch case 0x59: /* Evervision Display with FT5xx6 TS */ 963a2f39dacSMarco Felsch tsdata->version = EV_FT; 9649dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1); 965a2f39dacSMarco Felsch if (error) 966a2f39dacSMarco Felsch return error; 967a9f08ad7SWolfram Sang strscpy(fw_version, rdbuf, 1); 968a2f39dacSMarco Felsch snprintf(model_name, EDT_NAME_LEN, 969a2f39dacSMarco Felsch "EVERVISION-FT5726NEi"); 970a2f39dacSMarco Felsch break; 971169110c3SSimon Budig default: 972169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, 973169110c3SSimon Budig "generic ft5x06 (%02x)", 974169110c3SSimon Budig rdbuf[0]); 975169110c3SSimon Budig break; 976169110c3SSimon Budig } 977fd335ab0SLothar Waßmann } 97843c4d13eSSimon Budig 97943c4d13eSSimon Budig return 0; 98043c4d13eSSimon Budig } 98143c4d13eSSimon Budig 9822e23b7a9SDmitry Torokhov static void edt_ft5x06_ts_get_defaults(struct device *dev, 983dac90dc2SLothar Waßmann struct edt_ft5x06_ts_data *tsdata) 984dac90dc2SLothar Waßmann { 985fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 9869dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 9872e23b7a9SDmitry Torokhov u32 val; 9882e23b7a9SDmitry Torokhov int error; 989fd335ab0SLothar Waßmann 9902e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "threshold", &val); 991dc262dfaSPhilipp Zabel if (!error) { 9929dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_threshold, val); 993dc262dfaSPhilipp Zabel tsdata->threshold = val; 994dc262dfaSPhilipp Zabel } 9952e23b7a9SDmitry Torokhov 9962e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "gain", &val); 997dc262dfaSPhilipp Zabel if (!error) { 9989dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_gain, val); 999dc262dfaSPhilipp Zabel tsdata->gain = val; 1000dc262dfaSPhilipp Zabel } 10012e23b7a9SDmitry Torokhov 10022e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "offset", &val); 1003dc262dfaSPhilipp Zabel if (!error) { 1004255cdaf7SMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 10059dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset, val); 1006dc262dfaSPhilipp Zabel tsdata->offset = val; 1007dc262dfaSPhilipp Zabel } 1008b6eba860SMarco Felsch 1009b6eba860SMarco Felsch error = device_property_read_u32(dev, "offset-x", &val); 1010b6eba860SMarco Felsch if (!error) { 1011255cdaf7SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 10129dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_x, val); 1013b6eba860SMarco Felsch tsdata->offset_x = val; 1014b6eba860SMarco Felsch } 1015b6eba860SMarco Felsch 1016b6eba860SMarco Felsch error = device_property_read_u32(dev, "offset-y", &val); 1017b6eba860SMarco Felsch if (!error) { 1018255cdaf7SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 10199dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_y, val); 1020b6eba860SMarco Felsch tsdata->offset_y = val; 1021b6eba860SMarco Felsch } 1022dac90dc2SLothar Waßmann } 1023dac90dc2SLothar Waßmann 102403161a95SDmitry Torokhov static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) 102543c4d13eSSimon Budig { 1026fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 10279dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 10289dfd9708SDario Binacchi unsigned int val; 1029fd335ab0SLothar Waßmann 10309dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold); 10319dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain); 1032a2f39dacSMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 10339dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset); 1034b6eba860SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 10359dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x); 1036b6eba860SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 10379dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y); 1038fd335ab0SLothar Waßmann if (reg_addr->reg_report_rate != NO_REGISTER) 10399dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_report_rate, 10409dfd9708SDario Binacchi &tsdata->report_rate); 104103161a95SDmitry Torokhov tsdata->num_x = EDT_DEFAULT_NUM_X; 10429dfd9708SDario Binacchi if (reg_addr->reg_num_x != NO_REGISTER) { 10439dfd9708SDario Binacchi if (!regmap_read(regmap, reg_addr->reg_num_x, &val)) 10449dfd9708SDario Binacchi tsdata->num_x = val; 10459dfd9708SDario Binacchi } 104603161a95SDmitry Torokhov tsdata->num_y = EDT_DEFAULT_NUM_Y; 10479dfd9708SDario Binacchi if (reg_addr->reg_num_y != NO_REGISTER) { 10489dfd9708SDario Binacchi if (!regmap_read(regmap, reg_addr->reg_num_y, &val)) 10499dfd9708SDario Binacchi tsdata->num_y = val; 10509dfd9708SDario Binacchi } 1051fd335ab0SLothar Waßmann } 1052fd335ab0SLothar Waßmann 10530df28e71SDario Binacchi static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata) 10540df28e71SDario Binacchi { 10550df28e71SDario Binacchi int crclen; 10560df28e71SDario Binacchi 10570df28e71SDario Binacchi if (tsdata->version == EDT_M06) { 10580df28e71SDario Binacchi tsdata->tdata_cmd = 0xf9; 10590df28e71SDario Binacchi tsdata->tdata_offset = 5; 10600df28e71SDario Binacchi tsdata->point_len = 4; 10610df28e71SDario Binacchi crclen = 1; 10620df28e71SDario Binacchi } else { 10630df28e71SDario Binacchi tsdata->tdata_cmd = 0x0; 10640df28e71SDario Binacchi tsdata->tdata_offset = 3; 10650df28e71SDario Binacchi tsdata->point_len = 6; 10660df28e71SDario Binacchi crclen = 0; 10670df28e71SDario Binacchi } 10680df28e71SDario Binacchi 10690df28e71SDario Binacchi tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points + 10700df28e71SDario Binacchi tsdata->tdata_offset + crclen; 10710df28e71SDario Binacchi } 10720df28e71SDario Binacchi 107303161a95SDmitry Torokhov static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) 1074fd335ab0SLothar Waßmann { 1075fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 1076fd335ab0SLothar Waßmann 1077fd335ab0SLothar Waßmann switch (tsdata->version) { 1078169110c3SSimon Budig case EDT_M06: 1079fd335ab0SLothar Waßmann reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; 1080fd335ab0SLothar Waßmann reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; 1081fd335ab0SLothar Waßmann reg_addr->reg_gain = WORK_REGISTER_GAIN; 1082fd335ab0SLothar Waßmann reg_addr->reg_offset = WORK_REGISTER_OFFSET; 1083b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1084b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 1085fd335ab0SLothar Waßmann reg_addr->reg_num_x = WORK_REGISTER_NUM_X; 1086fd335ab0SLothar Waßmann reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; 1087fd335ab0SLothar Waßmann break; 1088fd335ab0SLothar Waßmann 1089169110c3SSimon Budig case EDT_M09: 1090aed5d0eeSSimon Budig case EDT_M12: 1091fd335ab0SLothar Waßmann reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; 109223ea98f4SDario Binacchi reg_addr->reg_report_rate = tsdata->version == EDT_M12 ? 109323ea98f4SDario Binacchi M12_REGISTER_REPORT_RATE : NO_REGISTER; 1094fd335ab0SLothar Waßmann reg_addr->reg_gain = M09_REGISTER_GAIN; 1095fd335ab0SLothar Waßmann reg_addr->reg_offset = M09_REGISTER_OFFSET; 1096b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1097b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 1098fd335ab0SLothar Waßmann reg_addr->reg_num_x = M09_REGISTER_NUM_X; 1099fd335ab0SLothar Waßmann reg_addr->reg_num_y = M09_REGISTER_NUM_Y; 1100fd335ab0SLothar Waßmann break; 1101169110c3SSimon Budig 1102a2f39dacSMarco Felsch case EV_FT: 1103a2f39dacSMarco Felsch reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; 110403161a95SDmitry Torokhov reg_addr->reg_report_rate = NO_REGISTER; 1105a2f39dacSMarco Felsch reg_addr->reg_gain = EV_REGISTER_GAIN; 1106a2f39dacSMarco Felsch reg_addr->reg_offset = NO_REGISTER; 1107b6eba860SMarco Felsch reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; 1108b6eba860SMarco Felsch reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; 1109a2f39dacSMarco Felsch reg_addr->reg_num_x = NO_REGISTER; 1110a2f39dacSMarco Felsch reg_addr->reg_num_y = NO_REGISTER; 1111a2f39dacSMarco Felsch break; 1112a2f39dacSMarco Felsch 1113169110c3SSimon Budig case GENERIC_FT: 1114169110c3SSimon Budig /* this is a guesswork */ 1115169110c3SSimon Budig reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; 111603161a95SDmitry Torokhov reg_addr->reg_report_rate = NO_REGISTER; 1117169110c3SSimon Budig reg_addr->reg_gain = M09_REGISTER_GAIN; 1118169110c3SSimon Budig reg_addr->reg_offset = M09_REGISTER_OFFSET; 1119b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1120b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 112103161a95SDmitry Torokhov reg_addr->reg_num_x = NO_REGISTER; 112203161a95SDmitry Torokhov reg_addr->reg_num_y = NO_REGISTER; 1123169110c3SSimon Budig break; 1124fd335ab0SLothar Waßmann } 112543c4d13eSSimon Budig } 112643c4d13eSSimon Budig 1127df4c40f4SStephan Gerhold static void edt_ft5x06_disable_regulators(void *arg) 11287448bfecSMylène Josserand { 11297448bfecSMylène Josserand struct edt_ft5x06_ts_data *data = arg; 11307448bfecSMylène Josserand 11317448bfecSMylène Josserand regulator_disable(data->vcc); 1132df4c40f4SStephan Gerhold regulator_disable(data->iovcc); 11337448bfecSMylène Josserand } 11347448bfecSMylène Josserand 1135e7c31218SUwe Kleine-König static int edt_ft5x06_ts_probe(struct i2c_client *client) 113643c4d13eSSimon Budig { 1137e7c31218SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client); 1138b1d2a3ecSFranklin S Cooper Jr const struct edt_i2c_chip_data *chip_data; 113943c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata; 11409dfd9708SDario Binacchi unsigned int val; 114143c4d13eSSimon Budig struct input_dev *input; 1142f0bef75cSDmitry Torokhov unsigned long irq_flags; 114343c4d13eSSimon Budig int error; 11445bcee83aSDario Binacchi u32 report_rate; 114543c4d13eSSimon Budig 114643c4d13eSSimon Budig dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); 114743c4d13eSSimon Budig 114802300bd6SLothar Waßmann tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); 114902300bd6SLothar Waßmann if (!tsdata) { 115043c4d13eSSimon Budig dev_err(&client->dev, "failed to allocate driver data.\n"); 115102300bd6SLothar Waßmann return -ENOMEM; 115202300bd6SLothar Waßmann } 115302300bd6SLothar Waßmann 11549dfd9708SDario Binacchi tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); 11559dfd9708SDario Binacchi if (IS_ERR(tsdata->regmap)) { 11569dfd9708SDario Binacchi dev_err(&client->dev, "regmap allocation failed\n"); 11579dfd9708SDario Binacchi return PTR_ERR(tsdata->regmap); 11589dfd9708SDario Binacchi } 11599dfd9708SDario Binacchi 1160fc226eb2SAndy Shevchenko chip_data = device_get_match_data(&client->dev); 1161b1d2a3ecSFranklin S Cooper Jr if (!chip_data) 1162b1d2a3ecSFranklin S Cooper Jr chip_data = (const struct edt_i2c_chip_data *)id->driver_data; 1163b1d2a3ecSFranklin S Cooper Jr if (!chip_data || !chip_data->max_support_points) { 1164b1d2a3ecSFranklin S Cooper Jr dev_err(&client->dev, "invalid or missing chip data\n"); 1165b1d2a3ecSFranklin S Cooper Jr return -EINVAL; 1166b1d2a3ecSFranklin S Cooper Jr } 1167b1d2a3ecSFranklin S Cooper Jr 1168b1d2a3ecSFranklin S Cooper Jr tsdata->max_support_points = chip_data->max_support_points; 1169b1d2a3ecSFranklin S Cooper Jr 11707448bfecSMylène Josserand tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); 11717448bfecSMylène Josserand if (IS_ERR(tsdata->vcc)) { 11727448bfecSMylène Josserand error = PTR_ERR(tsdata->vcc); 11737448bfecSMylène Josserand if (error != -EPROBE_DEFER) 11747448bfecSMylène Josserand dev_err(&client->dev, 11757448bfecSMylène Josserand "failed to request regulator: %d\n", error); 11767448bfecSMylène Josserand return error; 11777448bfecSMylène Josserand } 11787448bfecSMylène Josserand 1179df4c40f4SStephan Gerhold tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); 1180df4c40f4SStephan Gerhold if (IS_ERR(tsdata->iovcc)) { 1181df4c40f4SStephan Gerhold error = PTR_ERR(tsdata->iovcc); 1182df4c40f4SStephan Gerhold if (error != -EPROBE_DEFER) 1183df4c40f4SStephan Gerhold dev_err(&client->dev, 1184df4c40f4SStephan Gerhold "failed to request iovcc regulator: %d\n", error); 1185df4c40f4SStephan Gerhold return error; 1186df4c40f4SStephan Gerhold } 1187df4c40f4SStephan Gerhold 1188df4c40f4SStephan Gerhold error = regulator_enable(tsdata->iovcc); 1189df4c40f4SStephan Gerhold if (error < 0) { 1190df4c40f4SStephan Gerhold dev_err(&client->dev, "failed to enable iovcc: %d\n", error); 1191df4c40f4SStephan Gerhold return error; 1192df4c40f4SStephan Gerhold } 1193df4c40f4SStephan Gerhold 1194df4c40f4SStephan Gerhold /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ 1195df4c40f4SStephan Gerhold usleep_range(10, 100); 1196df4c40f4SStephan Gerhold 11977448bfecSMylène Josserand error = regulator_enable(tsdata->vcc); 11987448bfecSMylène Josserand if (error < 0) { 11997448bfecSMylène Josserand dev_err(&client->dev, "failed to enable vcc: %d\n", error); 1200df4c40f4SStephan Gerhold regulator_disable(tsdata->iovcc); 12017448bfecSMylène Josserand return error; 12027448bfecSMylène Josserand } 12037448bfecSMylène Josserand 12047448bfecSMylène Josserand error = devm_add_action_or_reset(&client->dev, 1205df4c40f4SStephan Gerhold edt_ft5x06_disable_regulators, 12067448bfecSMylène Josserand tsdata); 12077448bfecSMylène Josserand if (error) 12087448bfecSMylène Josserand return error; 12097448bfecSMylène Josserand 121013c23cd1SFranklin S Cooper Jr tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev, 121113c23cd1SFranklin S Cooper Jr "reset", GPIOD_OUT_HIGH); 121213c23cd1SFranklin S Cooper Jr if (IS_ERR(tsdata->reset_gpio)) { 121313c23cd1SFranklin S Cooper Jr error = PTR_ERR(tsdata->reset_gpio); 1214dac90dc2SLothar Waßmann dev_err(&client->dev, 121513c23cd1SFranklin S Cooper Jr "Failed to request GPIO reset pin, error %d\n", error); 1216dac90dc2SLothar Waßmann return error; 1217dac90dc2SLothar Waßmann } 1218dac90dc2SLothar Waßmann 121913c23cd1SFranklin S Cooper Jr tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev, 122013c23cd1SFranklin S Cooper Jr "wake", GPIOD_OUT_LOW); 122113c23cd1SFranklin S Cooper Jr if (IS_ERR(tsdata->wake_gpio)) { 122213c23cd1SFranklin S Cooper Jr error = PTR_ERR(tsdata->wake_gpio); 1223dac90dc2SLothar Waßmann dev_err(&client->dev, 122413c23cd1SFranklin S Cooper Jr "Failed to request GPIO wake pin, error %d\n", error); 1225dac90dc2SLothar Waßmann return error; 1226dac90dc2SLothar Waßmann } 122713c23cd1SFranklin S Cooper Jr 122821d1611aSMarco Felsch /* 122921d1611aSMarco Felsch * Check which sleep modes we can support. Power-off requieres the 123021d1611aSMarco Felsch * reset-pin to ensure correct power-down/power-up behaviour. Start with 123121d1611aSMarco Felsch * the EDT_PMODE_POWEROFF test since this is the deepest possible sleep 123221d1611aSMarco Felsch * mode. 123321d1611aSMarco Felsch */ 123421d1611aSMarco Felsch if (tsdata->reset_gpio) 123521d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_POWEROFF; 123621d1611aSMarco Felsch else if (tsdata->wake_gpio) 123721d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_HIBERNATE; 123821d1611aSMarco Felsch else 123921d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_NOT_SUPPORTED; 124021d1611aSMarco Felsch 124113c23cd1SFranklin S Cooper Jr if (tsdata->wake_gpio) { 124213c23cd1SFranklin S Cooper Jr usleep_range(5000, 6000); 124313c23cd1SFranklin S Cooper Jr gpiod_set_value_cansleep(tsdata->wake_gpio, 1); 12445672bd30SPhilipp Puschmann usleep_range(5000, 6000); 124513c23cd1SFranklin S Cooper Jr } 124613c23cd1SFranklin S Cooper Jr 124713c23cd1SFranklin S Cooper Jr if (tsdata->reset_gpio) { 124813c23cd1SFranklin S Cooper Jr usleep_range(5000, 6000); 124913c23cd1SFranklin S Cooper Jr gpiod_set_value_cansleep(tsdata->reset_gpio, 0); 125013c23cd1SFranklin S Cooper Jr msleep(300); 1251dac90dc2SLothar Waßmann } 1252dac90dc2SLothar Waßmann 125302300bd6SLothar Waßmann input = devm_input_allocate_device(&client->dev); 125402300bd6SLothar Waßmann if (!input) { 125502300bd6SLothar Waßmann dev_err(&client->dev, "failed to allocate input device.\n"); 125602300bd6SLothar Waßmann return -ENOMEM; 125743c4d13eSSimon Budig } 125843c4d13eSSimon Budig 125943c4d13eSSimon Budig mutex_init(&tsdata->mutex); 126043c4d13eSSimon Budig tsdata->client = client; 126143c4d13eSSimon Budig tsdata->input = input; 126243c4d13eSSimon Budig tsdata->factory_mode = false; 12639dfd9708SDario Binacchi i2c_set_clientdata(client, tsdata); 126443c4d13eSSimon Budig 1265480343dcSDario Binacchi error = edt_ft5x06_ts_identify(client, tsdata); 126643c4d13eSSimon Budig if (error) { 126743c4d13eSSimon Budig dev_err(&client->dev, "touchscreen probe failed\n"); 126802300bd6SLothar Waßmann return error; 126943c4d13eSSimon Budig } 127043c4d13eSSimon Budig 1271e112324cSPhilipp Zabel /* 1272e112324cSPhilipp Zabel * Dummy read access. EP0700MLP1 returns bogus data on the first 1273e112324cSPhilipp Zabel * register read access and ignores writes. 1274e112324cSPhilipp Zabel */ 12759dfd9708SDario Binacchi regmap_read(tsdata->regmap, 0x00, &val); 1276e112324cSPhilipp Zabel 12770df28e71SDario Binacchi edt_ft5x06_ts_set_tdata_parameters(tsdata); 1278fd335ab0SLothar Waßmann edt_ft5x06_ts_set_regs(tsdata); 12792e23b7a9SDmitry Torokhov edt_ft5x06_ts_get_defaults(&client->dev, tsdata); 128043c4d13eSSimon Budig edt_ft5x06_ts_get_parameters(tsdata); 128143c4d13eSSimon Budig 12825bcee83aSDario Binacchi if (tsdata->reg_addr.reg_report_rate != NO_REGISTER && 12835bcee83aSDario Binacchi !device_property_read_u32(&client->dev, 12845bcee83aSDario Binacchi "report-rate-hz", &report_rate)) { 12855bcee83aSDario Binacchi if (tsdata->version == EDT_M06) 12865bcee83aSDario Binacchi tsdata->report_rate = clamp_val(report_rate, 30, 140); 12875bcee83aSDario Binacchi else 12885bcee83aSDario Binacchi tsdata->report_rate = clamp_val(report_rate, 1, 255); 12895bcee83aSDario Binacchi 12905bcee83aSDario Binacchi if (report_rate != tsdata->report_rate) 12915bcee83aSDario Binacchi dev_warn(&client->dev, 12925bcee83aSDario Binacchi "report-rate %dHz is unsupported, use %dHz\n", 12935bcee83aSDario Binacchi report_rate, tsdata->report_rate); 12945bcee83aSDario Binacchi 12955bcee83aSDario Binacchi if (tsdata->version == EDT_M06) 12965bcee83aSDario Binacchi tsdata->report_rate /= 10; 12975bcee83aSDario Binacchi 12989dfd9708SDario Binacchi regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate, 12995bcee83aSDario Binacchi tsdata->report_rate); 13005bcee83aSDario Binacchi } 13015bcee83aSDario Binacchi 130243c4d13eSSimon Budig dev_dbg(&client->dev, 130343c4d13eSSimon Budig "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", 1304480343dcSDario Binacchi tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y); 130543c4d13eSSimon Budig 130643c4d13eSSimon Budig input->name = tsdata->name; 130743c4d13eSSimon Budig input->id.bustype = BUS_I2C; 130843c4d13eSSimon Budig input->dev.parent = &client->dev; 130943c4d13eSSimon Budig 131043c4d13eSSimon Budig input_set_abs_params(input, ABS_MT_POSITION_X, 131143c4d13eSSimon Budig 0, tsdata->num_x * 64 - 1, 0, 0); 131243c4d13eSSimon Budig input_set_abs_params(input, ABS_MT_POSITION_Y, 131343c4d13eSSimon Budig 0, tsdata->num_y * 64 - 1, 0, 0); 13142c005598SMaxime Ripard 1315ad368eb2SHans de Goede touchscreen_parse_properties(input, true, &tsdata->prop); 13162c005598SMaxime Ripard 1317b1d2a3ecSFranklin S Cooper Jr error = input_mt_init_slots(input, tsdata->max_support_points, 1318b1d2a3ecSFranklin S Cooper Jr INPUT_MT_DIRECT); 131943c4d13eSSimon Budig if (error) { 132043c4d13eSSimon Budig dev_err(&client->dev, "Unable to init MT slots.\n"); 132102300bd6SLothar Waßmann return error; 132243c4d13eSSimon Budig } 132343c4d13eSSimon Budig 1324f0bef75cSDmitry Torokhov irq_flags = irq_get_trigger_type(client->irq); 1325f0bef75cSDmitry Torokhov if (irq_flags == IRQF_TRIGGER_NONE) 1326f0bef75cSDmitry Torokhov irq_flags = IRQF_TRIGGER_FALLING; 1327f0bef75cSDmitry Torokhov irq_flags |= IRQF_ONESHOT; 1328f0bef75cSDmitry Torokhov 1329f0bef75cSDmitry Torokhov error = devm_request_threaded_irq(&client->dev, client->irq, 1330f0bef75cSDmitry Torokhov NULL, edt_ft5x06_ts_isr, irq_flags, 133143c4d13eSSimon Budig client->name, tsdata); 133243c4d13eSSimon Budig if (error) { 133343c4d13eSSimon Budig dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); 133402300bd6SLothar Waßmann return error; 133543c4d13eSSimon Budig } 133643c4d13eSSimon Budig 1337e3adf559SAndi Shyti error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); 133843c4d13eSSimon Budig if (error) 133902300bd6SLothar Waßmann return error; 134043c4d13eSSimon Budig 134143c4d13eSSimon Budig error = input_register_device(input); 1342dac90dc2SLothar Waßmann if (error) 1343e3adf559SAndi Shyti return error; 134443c4d13eSSimon Budig 134543c4d13eSSimon Budig edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); 134643c4d13eSSimon Budig 134743c4d13eSSimon Budig dev_dbg(&client->dev, 1348dac90dc2SLothar Waßmann "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", 13498b58cc36SFranklin S Cooper Jr client->irq, 13508b58cc36SFranklin S Cooper Jr tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, 13518b58cc36SFranklin S Cooper Jr tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); 135243c4d13eSSimon Budig 135343c4d13eSSimon Budig return 0; 135443c4d13eSSimon Budig } 135543c4d13eSSimon Budig 1356ed5c2f5fSUwe Kleine-König static void edt_ft5x06_ts_remove(struct i2c_client *client) 135743c4d13eSSimon Budig { 135843c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 135943c4d13eSSimon Budig 136043c4d13eSSimon Budig edt_ft5x06_ts_teardown_debugfs(tsdata); 13619dfd9708SDario Binacchi regmap_exit(tsdata->regmap); 136243c4d13eSSimon Budig } 136343c4d13eSSimon Budig 13646e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_suspend(struct device *dev) 136521d1611aSMarco Felsch { 136621d1611aSMarco Felsch struct i2c_client *client = to_i2c_client(dev); 136721d1611aSMarco Felsch struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 136821d1611aSMarco Felsch struct gpio_desc *reset_gpio = tsdata->reset_gpio; 136921d1611aSMarco Felsch int ret; 137021d1611aSMarco Felsch 137121d1611aSMarco Felsch if (device_may_wakeup(dev)) 137221d1611aSMarco Felsch return 0; 137321d1611aSMarco Felsch 137421d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED) 137521d1611aSMarco Felsch return 0; 137621d1611aSMarco Felsch 137721d1611aSMarco Felsch /* Enter hibernate mode. */ 13789dfd9708SDario Binacchi ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE, 137921d1611aSMarco Felsch PMOD_REGISTER_HIBERNATE); 138021d1611aSMarco Felsch if (ret) 138121d1611aSMarco Felsch dev_warn(dev, "Failed to set hibernate mode\n"); 138221d1611aSMarco Felsch 138321d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_HIBERNATE) 138421d1611aSMarco Felsch return 0; 138521d1611aSMarco Felsch 138621d1611aSMarco Felsch /* 138721d1611aSMarco Felsch * Power-off according the datasheet. Cut the power may leaf the irq 138821d1611aSMarco Felsch * line in an undefined state depending on the host pull resistor 138921d1611aSMarco Felsch * settings. Disable the irq to avoid adjusting each host till the 139021d1611aSMarco Felsch * device is back in a full functional state. 139121d1611aSMarco Felsch */ 139221d1611aSMarco Felsch disable_irq(tsdata->client->irq); 139321d1611aSMarco Felsch 139421d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 1); 139521d1611aSMarco Felsch usleep_range(1000, 2000); 139621d1611aSMarco Felsch 139721d1611aSMarco Felsch ret = regulator_disable(tsdata->vcc); 139821d1611aSMarco Felsch if (ret) 139921d1611aSMarco Felsch dev_warn(dev, "Failed to disable vcc\n"); 1400df4c40f4SStephan Gerhold ret = regulator_disable(tsdata->iovcc); 1401df4c40f4SStephan Gerhold if (ret) 1402df4c40f4SStephan Gerhold dev_warn(dev, "Failed to disable iovcc\n"); 140321d1611aSMarco Felsch 140421d1611aSMarco Felsch return 0; 140521d1611aSMarco Felsch } 140621d1611aSMarco Felsch 14076e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_resume(struct device *dev) 140821d1611aSMarco Felsch { 140921d1611aSMarco Felsch struct i2c_client *client = to_i2c_client(dev); 141021d1611aSMarco Felsch struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 141121d1611aSMarco Felsch int ret = 0; 141221d1611aSMarco Felsch 141321d1611aSMarco Felsch if (device_may_wakeup(dev)) 141421d1611aSMarco Felsch return 0; 141521d1611aSMarco Felsch 141621d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED) 141721d1611aSMarco Felsch return 0; 141821d1611aSMarco Felsch 141921d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_POWEROFF) { 142021d1611aSMarco Felsch struct gpio_desc *reset_gpio = tsdata->reset_gpio; 142121d1611aSMarco Felsch 142221d1611aSMarco Felsch /* 142321d1611aSMarco Felsch * We can't check if the regulator is a dummy or a real 142421d1611aSMarco Felsch * regulator. So we need to specify the 5ms reset time (T_rst) 142521d1611aSMarco Felsch * here instead of the 100us T_rtp time. We also need to wait 142621d1611aSMarco Felsch * 300ms in case it was a real supply and the power was cutted 142721d1611aSMarco Felsch * of. Toggle the reset pin is also a way to exit the hibernate 142821d1611aSMarco Felsch * mode. 142921d1611aSMarco Felsch */ 143021d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 1); 143121d1611aSMarco Felsch usleep_range(5000, 6000); 143221d1611aSMarco Felsch 1433df4c40f4SStephan Gerhold ret = regulator_enable(tsdata->iovcc); 1434df4c40f4SStephan Gerhold if (ret) { 1435df4c40f4SStephan Gerhold dev_err(dev, "Failed to enable iovcc\n"); 1436df4c40f4SStephan Gerhold return ret; 1437df4c40f4SStephan Gerhold } 1438df4c40f4SStephan Gerhold 1439df4c40f4SStephan Gerhold /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ 1440df4c40f4SStephan Gerhold usleep_range(10, 100); 1441df4c40f4SStephan Gerhold 144221d1611aSMarco Felsch ret = regulator_enable(tsdata->vcc); 144321d1611aSMarco Felsch if (ret) { 144421d1611aSMarco Felsch dev_err(dev, "Failed to enable vcc\n"); 1445df4c40f4SStephan Gerhold regulator_disable(tsdata->iovcc); 144621d1611aSMarco Felsch return ret; 144721d1611aSMarco Felsch } 144821d1611aSMarco Felsch 144921d1611aSMarco Felsch usleep_range(1000, 2000); 145021d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 0); 145121d1611aSMarco Felsch msleep(300); 145221d1611aSMarco Felsch 145321d1611aSMarco Felsch edt_ft5x06_restore_reg_parameters(tsdata); 145421d1611aSMarco Felsch enable_irq(tsdata->client->irq); 145521d1611aSMarco Felsch 145621d1611aSMarco Felsch if (tsdata->factory_mode) 145721d1611aSMarco Felsch ret = edt_ft5x06_factory_mode(tsdata); 145821d1611aSMarco Felsch } else { 145921d1611aSMarco Felsch struct gpio_desc *wake_gpio = tsdata->wake_gpio; 146021d1611aSMarco Felsch 146121d1611aSMarco Felsch gpiod_set_value_cansleep(wake_gpio, 0); 146221d1611aSMarco Felsch usleep_range(5000, 6000); 146321d1611aSMarco Felsch gpiod_set_value_cansleep(wake_gpio, 1); 146421d1611aSMarco Felsch } 146521d1611aSMarco Felsch 146621d1611aSMarco Felsch return ret; 146721d1611aSMarco Felsch } 146821d1611aSMarco Felsch 14696e6ebfc5SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, 147021d1611aSMarco Felsch edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); 147121d1611aSMarco Felsch 1472b1d2a3ecSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5x06_data = { 1473b1d2a3ecSFranklin S Cooper Jr .max_support_points = 5, 1474b1d2a3ecSFranklin S Cooper Jr }; 1475b1d2a3ecSFranklin S Cooper Jr 1476af33e0adSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5506_data = { 1477af33e0adSFranklin S Cooper Jr .max_support_points = 10, 1478af33e0adSFranklin S Cooper Jr }; 1479af33e0adSFranklin S Cooper Jr 1480d1871654SHans de Goede static const struct edt_i2c_chip_data edt_ft6236_data = { 1481d1871654SHans de Goede .max_support_points = 2, 1482d1871654SHans de Goede }; 1483d1871654SHans de Goede 148443c4d13eSSimon Budig static const struct i2c_device_id edt_ft5x06_ts_id[] = { 1485b1d2a3ecSFranklin S Cooper Jr { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, 1486af33e0adSFranklin S Cooper Jr { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, 1487a2f39dacSMarco Felsch { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data }, 1488d1871654SHans de Goede /* Note no edt- prefix for compatibility with the ft6236.c driver */ 1489d1871654SHans de Goede { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, 14901730d814SLothar Waßmann { /* sentinel */ } 149143c4d13eSSimon Budig }; 149243c4d13eSSimon Budig MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); 149343c4d13eSSimon Budig 1494dac90dc2SLothar Waßmann static const struct of_device_id edt_ft5x06_of_match[] = { 1495b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data }, 1496b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, 1497b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, 1498af33e0adSFranklin S Cooper Jr { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, 1499a2f39dacSMarco Felsch { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, 1500d1871654SHans de Goede /* Note focaltech vendor prefix for compatibility with ft6236.c */ 1501d1871654SHans de Goede { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, 1502dac90dc2SLothar Waßmann { /* sentinel */ } 1503dac90dc2SLothar Waßmann }; 1504dac90dc2SLothar Waßmann MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); 1505dac90dc2SLothar Waßmann 150643c4d13eSSimon Budig static struct i2c_driver edt_ft5x06_ts_driver = { 150743c4d13eSSimon Budig .driver = { 150843c4d13eSSimon Budig .name = "edt_ft5x06", 1509fc226eb2SAndy Shevchenko .of_match_table = edt_ft5x06_of_match, 15106e6ebfc5SJonathan Cameron .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops), 15110f58daaaSAhmad Fatoum .probe_type = PROBE_PREFER_ASYNCHRONOUS, 151243c4d13eSSimon Budig }, 151343c4d13eSSimon Budig .id_table = edt_ft5x06_ts_id, 1514*d8bde56dSUwe Kleine-König .probe = edt_ft5x06_ts_probe, 15151cb0aa88SBill Pemberton .remove = edt_ft5x06_ts_remove, 151643c4d13eSSimon Budig }; 151743c4d13eSSimon Budig 151843c4d13eSSimon Budig module_i2c_driver(edt_ft5x06_ts_driver); 151943c4d13eSSimon Budig 152043c4d13eSSimon Budig MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>"); 152143c4d13eSSimon Budig MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver"); 15226d3a41abSAndy Shevchenko MODULE_LICENSE("GPL v2"); 1523