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) 6*9dfd9708SDario 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> 30*9dfd9708SDario 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 120*9dfd9708SDario Binacchi struct regmap *regmap; 121*9dfd9708SDario 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; 13843c4d13eSSimon Budig 13943c4d13eSSimon Budig char name[EDT_NAME_LEN]; 140480343dcSDario Binacchi char fw_version[EDT_NAME_LEN]; 141fd335ab0SLothar Waßmann 142fd335ab0SLothar Waßmann struct edt_reg_addr reg_addr; 143fd335ab0SLothar Waßmann enum edt_ver version; 144b777f93bSDario Binacchi unsigned int crc_errors; 145b777f93bSDario Binacchi unsigned int header_errors; 14643c4d13eSSimon Budig }; 14743c4d13eSSimon Budig 148b1d2a3ecSFranklin S Cooper Jr struct edt_i2c_chip_data { 149b1d2a3ecSFranklin S Cooper Jr int max_support_points; 150b1d2a3ecSFranklin S Cooper Jr }; 151b1d2a3ecSFranklin S Cooper Jr 152*9dfd9708SDario Binacchi static const struct regmap_config edt_ft5x06_i2c_regmap_config = { 153*9dfd9708SDario Binacchi .reg_bits = 8, 154*9dfd9708SDario Binacchi .val_bits = 8, 155*9dfd9708SDario Binacchi }; 15643c4d13eSSimon Budig 15743c4d13eSSimon Budig static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, 15843c4d13eSSimon Budig u8 *buf, int buflen) 15943c4d13eSSimon Budig { 16043c4d13eSSimon Budig int i; 16143c4d13eSSimon Budig u8 crc = 0; 16243c4d13eSSimon Budig 16343c4d13eSSimon Budig for (i = 0; i < buflen - 1; i++) 16443c4d13eSSimon Budig crc ^= buf[i]; 16543c4d13eSSimon Budig 16643c4d13eSSimon Budig if (crc != buf[buflen - 1]) { 167b777f93bSDario Binacchi tsdata->crc_errors++; 16843c4d13eSSimon Budig dev_err_ratelimited(&tsdata->client->dev, 16943c4d13eSSimon Budig "crc error: 0x%02x expected, got 0x%02x\n", 17043c4d13eSSimon Budig crc, buf[buflen - 1]); 17143c4d13eSSimon Budig return false; 17243c4d13eSSimon Budig } 17343c4d13eSSimon Budig 17443c4d13eSSimon Budig return true; 17543c4d13eSSimon Budig } 17643c4d13eSSimon Budig 177*9dfd9708SDario Binacchi static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, 178*9dfd9708SDario Binacchi void *val_buf, size_t val_size) 179*9dfd9708SDario Binacchi { 180*9dfd9708SDario Binacchi struct device *dev = context; 181*9dfd9708SDario Binacchi struct i2c_client *i2c = to_i2c_client(dev); 182*9dfd9708SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); 183*9dfd9708SDario Binacchi struct i2c_msg xfer[2]; 184*9dfd9708SDario Binacchi bool reg_read = false; 185*9dfd9708SDario Binacchi u8 addr; 186*9dfd9708SDario Binacchi u8 wlen; 187*9dfd9708SDario Binacchi u8 wbuf[4], rbuf[3]; 188*9dfd9708SDario Binacchi int ret; 189*9dfd9708SDario Binacchi 190*9dfd9708SDario Binacchi addr = *((u8 *)reg_buf); 191*9dfd9708SDario Binacchi wbuf[0] = addr; 192*9dfd9708SDario Binacchi switch (addr) { 193*9dfd9708SDario Binacchi case 0xf5: 194*9dfd9708SDario Binacchi wlen = 3; 195*9dfd9708SDario Binacchi wbuf[0] = 0xf5; 196*9dfd9708SDario Binacchi wbuf[1] = 0xe; 197*9dfd9708SDario Binacchi wbuf[2] = *((u8 *)val_buf); 198*9dfd9708SDario Binacchi break; 199*9dfd9708SDario Binacchi case 0xf9: 200*9dfd9708SDario Binacchi wlen = 1; 201*9dfd9708SDario Binacchi break; 202*9dfd9708SDario Binacchi default: 203*9dfd9708SDario Binacchi wlen = 2; 204*9dfd9708SDario Binacchi reg_read = true; 205*9dfd9708SDario Binacchi wbuf[0] = M06_REG_CMD(tsdata->factory_mode); 206*9dfd9708SDario Binacchi wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); 207*9dfd9708SDario Binacchi wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; 208*9dfd9708SDario Binacchi } 209*9dfd9708SDario Binacchi 210*9dfd9708SDario Binacchi xfer[0].addr = i2c->addr; 211*9dfd9708SDario Binacchi xfer[0].flags = 0; 212*9dfd9708SDario Binacchi xfer[0].len = wlen; 213*9dfd9708SDario Binacchi xfer[0].buf = wbuf; 214*9dfd9708SDario Binacchi 215*9dfd9708SDario Binacchi xfer[1].addr = i2c->addr; 216*9dfd9708SDario Binacchi xfer[1].flags = I2C_M_RD; 217*9dfd9708SDario Binacchi xfer[1].len = reg_read ? 2 : val_size; 218*9dfd9708SDario Binacchi xfer[1].buf = reg_read ? rbuf : val_buf; 219*9dfd9708SDario Binacchi 220*9dfd9708SDario Binacchi ret = i2c_transfer(i2c->adapter, xfer, 2); 221*9dfd9708SDario Binacchi if (ret != 2) { 222*9dfd9708SDario Binacchi if (ret < 0) 223*9dfd9708SDario Binacchi return ret; 224*9dfd9708SDario Binacchi 225*9dfd9708SDario Binacchi return -EIO; 226*9dfd9708SDario Binacchi } 227*9dfd9708SDario Binacchi 228*9dfd9708SDario Binacchi if (addr == 0xf9) { 229*9dfd9708SDario Binacchi u8 *buf = (u8 *)val_buf; 230*9dfd9708SDario Binacchi 231*9dfd9708SDario Binacchi if (buf[0] != 0xaa || buf[1] != 0xaa || 232*9dfd9708SDario Binacchi buf[2] != val_size) { 233*9dfd9708SDario Binacchi tsdata->header_errors++; 234*9dfd9708SDario Binacchi dev_err_ratelimited(dev, 235*9dfd9708SDario Binacchi "Unexpected header: %02x%02x%02x\n", 236*9dfd9708SDario Binacchi buf[0], buf[1], buf[2]); 237*9dfd9708SDario Binacchi return -EIO; 238*9dfd9708SDario Binacchi } 239*9dfd9708SDario Binacchi 240*9dfd9708SDario Binacchi if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size)) 241*9dfd9708SDario Binacchi return -EIO; 242*9dfd9708SDario Binacchi } else if (reg_read) { 243*9dfd9708SDario Binacchi u8 crc = wbuf[0] ^ wbuf[1] ^ rbuf[0]; 244*9dfd9708SDario Binacchi 245*9dfd9708SDario Binacchi if (crc != rbuf[1]) { 246*9dfd9708SDario Binacchi dev_err(dev, "crc error: 0x%02x expected, got 0x%02x\n", 247*9dfd9708SDario Binacchi crc, rbuf[1]); 248*9dfd9708SDario Binacchi return -EIO; 249*9dfd9708SDario Binacchi } 250*9dfd9708SDario Binacchi 251*9dfd9708SDario Binacchi *((u8 *)val_buf) = rbuf[0]; 252*9dfd9708SDario Binacchi } 253*9dfd9708SDario Binacchi 254*9dfd9708SDario Binacchi return 0; 255*9dfd9708SDario Binacchi } 256*9dfd9708SDario Binacchi 257*9dfd9708SDario Binacchi static int edt_M06_i2c_write(void *context, const void *data, size_t count) 258*9dfd9708SDario Binacchi { 259*9dfd9708SDario Binacchi struct device *dev = context; 260*9dfd9708SDario Binacchi struct i2c_client *i2c = to_i2c_client(dev); 261*9dfd9708SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); 262*9dfd9708SDario Binacchi u8 addr, val; 263*9dfd9708SDario Binacchi u8 wbuf[4]; 264*9dfd9708SDario Binacchi struct i2c_msg xfer; 265*9dfd9708SDario Binacchi int ret; 266*9dfd9708SDario Binacchi 267*9dfd9708SDario Binacchi addr = *((u8 *)data); 268*9dfd9708SDario Binacchi val = *((u8 *)data + 1); 269*9dfd9708SDario Binacchi 270*9dfd9708SDario Binacchi wbuf[0] = M06_REG_CMD(tsdata->factory_mode); 271*9dfd9708SDario Binacchi wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); 272*9dfd9708SDario Binacchi wbuf[2] = val; 273*9dfd9708SDario Binacchi wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2]; 274*9dfd9708SDario Binacchi 275*9dfd9708SDario Binacchi xfer.addr = i2c->addr; 276*9dfd9708SDario Binacchi xfer.flags = 0; 277*9dfd9708SDario Binacchi xfer.len = 4; 278*9dfd9708SDario Binacchi xfer.buf = wbuf; 279*9dfd9708SDario Binacchi 280*9dfd9708SDario Binacchi ret = i2c_transfer(i2c->adapter, &xfer, 1); 281*9dfd9708SDario Binacchi if (ret != 1) { 282*9dfd9708SDario Binacchi if (ret < 0) 283*9dfd9708SDario Binacchi return ret; 284*9dfd9708SDario Binacchi 285*9dfd9708SDario Binacchi return -EIO; 286*9dfd9708SDario Binacchi } 287*9dfd9708SDario Binacchi 288*9dfd9708SDario Binacchi return 0; 289*9dfd9708SDario Binacchi } 290*9dfd9708SDario Binacchi 291*9dfd9708SDario Binacchi static const struct regmap_config edt_M06_i2c_regmap_config = { 292*9dfd9708SDario Binacchi .reg_bits = 8, 293*9dfd9708SDario Binacchi .val_bits = 8, 294*9dfd9708SDario Binacchi .read = edt_M06_i2c_read, 295*9dfd9708SDario Binacchi .write = edt_M06_i2c_write, 296*9dfd9708SDario Binacchi }; 297*9dfd9708SDario Binacchi 29843c4d13eSSimon Budig static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) 29943c4d13eSSimon Budig { 30043c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = dev_id; 30143c4d13eSSimon Budig struct device *dev = &tsdata->client->dev; 302fd335ab0SLothar Waßmann u8 cmd; 3039378c025SFranklin S Cooper Jr u8 rdbuf[63]; 30443c4d13eSSimon Budig int i, type, x, y, id; 305c789f1fbSFranklin S Cooper Jr int offset, tplen, datalen, crclen; 30643c4d13eSSimon Budig int error; 30743c4d13eSSimon Budig 308fd335ab0SLothar Waßmann switch (tsdata->version) { 309169110c3SSimon Budig case EDT_M06: 310fd335ab0SLothar Waßmann cmd = 0xf9; /* tell the controller to send touch data */ 311fd335ab0SLothar Waßmann offset = 5; /* where the actual touch data starts */ 312fd335ab0SLothar Waßmann tplen = 4; /* data comes in so called frames */ 313c789f1fbSFranklin S Cooper Jr crclen = 1; /* length of the crc data */ 314fd335ab0SLothar Waßmann break; 315fd335ab0SLothar Waßmann 316169110c3SSimon Budig case EDT_M09: 317aed5d0eeSSimon Budig case EDT_M12: 318a2f39dacSMarco Felsch case EV_FT: 319169110c3SSimon Budig case GENERIC_FT: 3209378c025SFranklin S Cooper Jr cmd = 0x0; 3219378c025SFranklin S Cooper Jr offset = 3; 322fd335ab0SLothar Waßmann tplen = 6; 323c789f1fbSFranklin S Cooper Jr crclen = 0; 324fd335ab0SLothar Waßmann break; 325fd335ab0SLothar Waßmann 326fd335ab0SLothar Waßmann default: 327fd335ab0SLothar Waßmann goto out; 328fd335ab0SLothar Waßmann } 329fd335ab0SLothar Waßmann 33043c4d13eSSimon Budig memset(rdbuf, 0, sizeof(rdbuf)); 331b1d2a3ecSFranklin S Cooper Jr datalen = tplen * tsdata->max_support_points + offset + crclen; 33243c4d13eSSimon Budig 333*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, cmd, rdbuf, datalen); 33443c4d13eSSimon Budig if (error) { 33543c4d13eSSimon Budig dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", 33643c4d13eSSimon Budig error); 33743c4d13eSSimon Budig goto out; 33843c4d13eSSimon Budig } 33943c4d13eSSimon Budig 340b1d2a3ecSFranklin S Cooper Jr for (i = 0; i < tsdata->max_support_points; i++) { 341fd335ab0SLothar Waßmann u8 *buf = &rdbuf[i * tplen + offset]; 34243c4d13eSSimon Budig 34343c4d13eSSimon Budig type = buf[0] >> 6; 34443c4d13eSSimon Budig /* ignore Reserved events */ 34543c4d13eSSimon Budig if (type == TOUCH_EVENT_RESERVED) 34643c4d13eSSimon Budig continue; 34743c4d13eSSimon Budig 348fd335ab0SLothar Waßmann /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ 349169110c3SSimon Budig if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) 350ee3e946eSLothar Waßmann continue; 351ee3e946eSLothar Waßmann 3521b9c698cSDmitry Torokhov x = get_unaligned_be16(buf) & 0x0fff; 3531b9c698cSDmitry Torokhov y = get_unaligned_be16(buf + 2) & 0x0fff; 354a2f39dacSMarco Felsch /* The FT5x26 send the y coordinate first */ 355a2f39dacSMarco Felsch if (tsdata->version == EV_FT) 356a2f39dacSMarco Felsch swap(x, y); 357a2f39dacSMarco Felsch 35843c4d13eSSimon Budig id = (buf[2] >> 4) & 0x0f; 35943c4d13eSSimon Budig 36043c4d13eSSimon Budig input_mt_slot(tsdata->input, id); 36117b92927SDmitry Torokhov if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, 36217b92927SDmitry Torokhov type != TOUCH_EVENT_UP)) 36317b92927SDmitry Torokhov touchscreen_report_pos(tsdata->input, &tsdata->prop, 36417b92927SDmitry Torokhov x, y, true); 36543c4d13eSSimon Budig } 36643c4d13eSSimon Budig 36743c4d13eSSimon Budig input_mt_report_pointer_emulation(tsdata->input, true); 36843c4d13eSSimon Budig input_sync(tsdata->input); 36943c4d13eSSimon Budig 37043c4d13eSSimon Budig out: 37143c4d13eSSimon Budig return IRQ_HANDLED; 37243c4d13eSSimon Budig } 37343c4d13eSSimon Budig 37443c4d13eSSimon Budig struct edt_ft5x06_attribute { 37543c4d13eSSimon Budig struct device_attribute dattr; 37643c4d13eSSimon Budig size_t field_offset; 37743c4d13eSSimon Budig u8 limit_low; 37843c4d13eSSimon Budig u8 limit_high; 379fd335ab0SLothar Waßmann u8 addr_m06; 380fd335ab0SLothar Waßmann u8 addr_m09; 3812ebc1919SMarco Felsch u8 addr_ev; 38243c4d13eSSimon Budig }; 38343c4d13eSSimon Budig 3842ebc1919SMarco Felsch #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \ 385fd335ab0SLothar Waßmann _limit_low, _limit_high) \ 38643c4d13eSSimon Budig struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ 38743c4d13eSSimon Budig .dattr = __ATTR(_field, _mode, \ 38843c4d13eSSimon Budig edt_ft5x06_setting_show, \ 38943c4d13eSSimon Budig edt_ft5x06_setting_store), \ 390fd335ab0SLothar Waßmann .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ 391fd335ab0SLothar Waßmann .addr_m06 = _addr_m06, \ 392fd335ab0SLothar Waßmann .addr_m09 = _addr_m09, \ 3932ebc1919SMarco Felsch .addr_ev = _addr_ev, \ 39443c4d13eSSimon Budig .limit_low = _limit_low, \ 39543c4d13eSSimon Budig .limit_high = _limit_high, \ 39643c4d13eSSimon Budig } 39743c4d13eSSimon Budig 39843c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_show(struct device *dev, 39943c4d13eSSimon Budig struct device_attribute *dattr, 40043c4d13eSSimon Budig char *buf) 40143c4d13eSSimon Budig { 40243c4d13eSSimon Budig struct i2c_client *client = to_i2c_client(dev); 40343c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 40443c4d13eSSimon Budig struct edt_ft5x06_attribute *attr = 40543c4d13eSSimon Budig container_of(dattr, struct edt_ft5x06_attribute, dattr); 4061730d814SLothar Waßmann u8 *field = (u8 *)tsdata + attr->field_offset; 407*9dfd9708SDario Binacchi unsigned int val; 40843c4d13eSSimon Budig size_t count = 0; 40943c4d13eSSimon Budig int error = 0; 410fd335ab0SLothar Waßmann u8 addr; 41143c4d13eSSimon Budig 41243c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 41343c4d13eSSimon Budig 41443c4d13eSSimon Budig if (tsdata->factory_mode) { 41543c4d13eSSimon Budig error = -EIO; 41643c4d13eSSimon Budig goto out; 41743c4d13eSSimon Budig } 41843c4d13eSSimon Budig 419fd335ab0SLothar Waßmann switch (tsdata->version) { 420169110c3SSimon Budig case EDT_M06: 421fd335ab0SLothar Waßmann addr = attr->addr_m06; 422fd335ab0SLothar Waßmann break; 423fd335ab0SLothar Waßmann 424169110c3SSimon Budig case EDT_M09: 425aed5d0eeSSimon Budig case EDT_M12: 426169110c3SSimon Budig case GENERIC_FT: 427fd335ab0SLothar Waßmann addr = attr->addr_m09; 428fd335ab0SLothar Waßmann break; 429fd335ab0SLothar Waßmann 4302ebc1919SMarco Felsch case EV_FT: 4312ebc1919SMarco Felsch addr = attr->addr_ev; 4322ebc1919SMarco Felsch break; 4332ebc1919SMarco Felsch 434fd335ab0SLothar Waßmann default: 435fd335ab0SLothar Waßmann error = -ENODEV; 436fd335ab0SLothar Waßmann goto out; 437fd335ab0SLothar Waßmann } 438fd335ab0SLothar Waßmann 439fd335ab0SLothar Waßmann if (addr != NO_REGISTER) { 440*9dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, addr, &val); 441*9dfd9708SDario Binacchi if (error) { 44243c4d13eSSimon Budig dev_err(&tsdata->client->dev, 44343c4d13eSSimon Budig "Failed to fetch attribute %s, error %d\n", 44443c4d13eSSimon Budig dattr->attr.name, error); 44543c4d13eSSimon Budig goto out; 44643c4d13eSSimon Budig } 447fd335ab0SLothar Waßmann } else { 448fd335ab0SLothar Waßmann val = *field; 449fd335ab0SLothar Waßmann } 45043c4d13eSSimon Budig 45143c4d13eSSimon Budig if (val != *field) { 45243c4d13eSSimon Budig dev_warn(&tsdata->client->dev, 45343c4d13eSSimon Budig "%s: read (%d) and stored value (%d) differ\n", 45443c4d13eSSimon Budig dattr->attr.name, val, *field); 45543c4d13eSSimon Budig *field = val; 45643c4d13eSSimon Budig } 45743c4d13eSSimon Budig 45843c4d13eSSimon Budig count = scnprintf(buf, PAGE_SIZE, "%d\n", val); 45943c4d13eSSimon Budig out: 46043c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 46143c4d13eSSimon Budig return error ?: count; 46243c4d13eSSimon Budig } 46343c4d13eSSimon Budig 46443c4d13eSSimon Budig static ssize_t edt_ft5x06_setting_store(struct device *dev, 46543c4d13eSSimon Budig struct device_attribute *dattr, 46643c4d13eSSimon Budig const char *buf, size_t count) 46743c4d13eSSimon Budig { 46843c4d13eSSimon Budig struct i2c_client *client = to_i2c_client(dev); 46943c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 47043c4d13eSSimon Budig struct edt_ft5x06_attribute *attr = 47143c4d13eSSimon Budig container_of(dattr, struct edt_ft5x06_attribute, dattr); 4721730d814SLothar Waßmann u8 *field = (u8 *)tsdata + attr->field_offset; 47343c4d13eSSimon Budig unsigned int val; 47443c4d13eSSimon Budig int error; 475fd335ab0SLothar Waßmann u8 addr; 47643c4d13eSSimon Budig 47743c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 47843c4d13eSSimon Budig 47943c4d13eSSimon Budig if (tsdata->factory_mode) { 48043c4d13eSSimon Budig error = -EIO; 48143c4d13eSSimon Budig goto out; 48243c4d13eSSimon Budig } 48343c4d13eSSimon Budig 48443c4d13eSSimon Budig error = kstrtouint(buf, 0, &val); 48543c4d13eSSimon Budig if (error) 48643c4d13eSSimon Budig goto out; 48743c4d13eSSimon Budig 48843c4d13eSSimon Budig if (val < attr->limit_low || val > attr->limit_high) { 48943c4d13eSSimon Budig error = -ERANGE; 49043c4d13eSSimon Budig goto out; 49143c4d13eSSimon Budig } 49243c4d13eSSimon Budig 493fd335ab0SLothar Waßmann switch (tsdata->version) { 494169110c3SSimon Budig case EDT_M06: 495fd335ab0SLothar Waßmann addr = attr->addr_m06; 496fd335ab0SLothar Waßmann break; 497fd335ab0SLothar Waßmann 498169110c3SSimon Budig case EDT_M09: 499aed5d0eeSSimon Budig case EDT_M12: 500169110c3SSimon Budig case GENERIC_FT: 501fd335ab0SLothar Waßmann addr = attr->addr_m09; 502fd335ab0SLothar Waßmann break; 503fd335ab0SLothar Waßmann 5042ebc1919SMarco Felsch case EV_FT: 5052ebc1919SMarco Felsch addr = attr->addr_ev; 5062ebc1919SMarco Felsch break; 5072ebc1919SMarco Felsch 508fd335ab0SLothar Waßmann default: 509fd335ab0SLothar Waßmann error = -ENODEV; 510fd335ab0SLothar Waßmann goto out; 511fd335ab0SLothar Waßmann } 512fd335ab0SLothar Waßmann 513fd335ab0SLothar Waßmann if (addr != NO_REGISTER) { 514*9dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, addr, val); 51543c4d13eSSimon Budig if (error) { 51643c4d13eSSimon Budig dev_err(&tsdata->client->dev, 51743c4d13eSSimon Budig "Failed to update attribute %s, error: %d\n", 51843c4d13eSSimon Budig dattr->attr.name, error); 51943c4d13eSSimon Budig goto out; 52043c4d13eSSimon Budig } 521fd335ab0SLothar Waßmann } 52243c4d13eSSimon Budig *field = val; 52343c4d13eSSimon Budig 52443c4d13eSSimon Budig out: 52543c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 52643c4d13eSSimon Budig return error ?: count; 52743c4d13eSSimon Budig } 52843c4d13eSSimon Budig 529aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-5 */ 530fd335ab0SLothar Waßmann static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 5312ebc1919SMarco Felsch M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31); 532aed5d0eeSSimon Budig /* m06, m09: range 0-31, m12: range 0-16 */ 533fd335ab0SLothar Waßmann static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 5342ebc1919SMarco Felsch M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); 535b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */ 536b6eba860SMarco Felsch static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, 537b6eba860SMarco Felsch EV_REGISTER_OFFSET_X, 0, 80); 538b6eba860SMarco Felsch /* m06, m09, m12: no supported, ev_ft: range 0-80 */ 539b6eba860SMarco Felsch static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, 540b6eba860SMarco Felsch EV_REGISTER_OFFSET_Y, 0, 80); 541aed5d0eeSSimon Budig /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ 542fd335ab0SLothar Waßmann static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, 5432ebc1919SMarco Felsch M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); 54423ea98f4SDario Binacchi /* m06: range 3 to 14, m12: range 1 to 255 */ 545fd335ab0SLothar Waßmann static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, 54623ea98f4SDario Binacchi M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255); 54743c4d13eSSimon Budig 54860790a58SDario Binacchi static ssize_t model_show(struct device *dev, struct device_attribute *attr, 54960790a58SDario Binacchi char *buf) 55060790a58SDario Binacchi { 55160790a58SDario Binacchi struct i2c_client *client = to_i2c_client(dev); 55260790a58SDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 55360790a58SDario Binacchi 55460790a58SDario Binacchi return sysfs_emit(buf, "%s\n", tsdata->name); 55560790a58SDario Binacchi } 55660790a58SDario Binacchi 55760790a58SDario Binacchi static DEVICE_ATTR_RO(model); 55860790a58SDario Binacchi 559480343dcSDario Binacchi static ssize_t fw_version_show(struct device *dev, 560480343dcSDario Binacchi struct device_attribute *attr, char *buf) 561480343dcSDario Binacchi { 562480343dcSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 563480343dcSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 564480343dcSDario Binacchi 565480343dcSDario Binacchi return sysfs_emit(buf, "%s\n", tsdata->fw_version); 566480343dcSDario Binacchi } 567480343dcSDario Binacchi 568480343dcSDario Binacchi static DEVICE_ATTR_RO(fw_version); 569480343dcSDario Binacchi 570b777f93bSDario Binacchi /* m06 only */ 571b777f93bSDario Binacchi static ssize_t header_errors_show(struct device *dev, 572b777f93bSDario Binacchi struct device_attribute *attr, char *buf) 573b777f93bSDario Binacchi { 574b777f93bSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 575b777f93bSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 576b777f93bSDario Binacchi 577b777f93bSDario Binacchi return sysfs_emit(buf, "%d\n", tsdata->header_errors); 578b777f93bSDario Binacchi } 579b777f93bSDario Binacchi 580b777f93bSDario Binacchi static DEVICE_ATTR_RO(header_errors); 581b777f93bSDario Binacchi 582b777f93bSDario Binacchi /* m06 only */ 583b777f93bSDario Binacchi static ssize_t crc_errors_show(struct device *dev, 584b777f93bSDario Binacchi struct device_attribute *attr, char *buf) 585b777f93bSDario Binacchi { 586b777f93bSDario Binacchi struct i2c_client *client = to_i2c_client(dev); 587b777f93bSDario Binacchi struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 588b777f93bSDario Binacchi 589b777f93bSDario Binacchi return sysfs_emit(buf, "%d\n", tsdata->crc_errors); 590b777f93bSDario Binacchi } 591b777f93bSDario Binacchi 592b777f93bSDario Binacchi static DEVICE_ATTR_RO(crc_errors); 593b777f93bSDario Binacchi 59443c4d13eSSimon Budig static struct attribute *edt_ft5x06_attrs[] = { 59543c4d13eSSimon Budig &edt_ft5x06_attr_gain.dattr.attr, 59643c4d13eSSimon Budig &edt_ft5x06_attr_offset.dattr.attr, 597b6eba860SMarco Felsch &edt_ft5x06_attr_offset_x.dattr.attr, 598b6eba860SMarco Felsch &edt_ft5x06_attr_offset_y.dattr.attr, 59943c4d13eSSimon Budig &edt_ft5x06_attr_threshold.dattr.attr, 60043c4d13eSSimon Budig &edt_ft5x06_attr_report_rate.dattr.attr, 60160790a58SDario Binacchi &dev_attr_model.attr, 602480343dcSDario Binacchi &dev_attr_fw_version.attr, 603b777f93bSDario Binacchi &dev_attr_header_errors.attr, 604b777f93bSDario Binacchi &dev_attr_crc_errors.attr, 60543c4d13eSSimon Budig NULL 60643c4d13eSSimon Budig }; 60743c4d13eSSimon Budig 60843c4d13eSSimon Budig static const struct attribute_group edt_ft5x06_attr_group = { 60943c4d13eSSimon Budig .attrs = edt_ft5x06_attrs, 61043c4d13eSSimon Budig }; 61143c4d13eSSimon Budig 612f4ee52f3SMarco Felsch static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) 613f4ee52f3SMarco Felsch { 614f4ee52f3SMarco Felsch struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 615*9dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 616f4ee52f3SMarco Felsch 617*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold); 618*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_gain, tsdata->gain); 619f4ee52f3SMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 620*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset, tsdata->offset); 621f4ee52f3SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 622*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x); 623f4ee52f3SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 624*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y); 625f4ee52f3SMarco Felsch if (reg_addr->reg_report_rate != NO_REGISTER) 626*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_report_rate, 627f4ee52f3SMarco Felsch tsdata->report_rate); 628f4ee52f3SMarco Felsch } 629f4ee52f3SMarco Felsch 63043c4d13eSSimon Budig #ifdef CONFIG_DEBUG_FS 63143c4d13eSSimon Budig static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) 63243c4d13eSSimon Budig { 63343c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 63443c4d13eSSimon Budig int retries = EDT_SWITCH_MODE_RETRIES; 635*9dfd9708SDario Binacchi unsigned int val; 63643c4d13eSSimon Budig int error; 63743c4d13eSSimon Budig 6384b3e910dSDmitry Torokhov if (tsdata->version != EDT_M06) { 6394b3e910dSDmitry Torokhov dev_err(&client->dev, 6404b3e910dSDmitry Torokhov "No factory mode support for non-M06 devices\n"); 6414b3e910dSDmitry Torokhov return -EINVAL; 6424b3e910dSDmitry Torokhov } 6434b3e910dSDmitry Torokhov 64443c4d13eSSimon Budig disable_irq(client->irq); 64543c4d13eSSimon Budig 64643c4d13eSSimon Budig if (!tsdata->raw_buffer) { 64743c4d13eSSimon Budig tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * 64843c4d13eSSimon Budig sizeof(u16); 64943c4d13eSSimon Budig tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL); 65043c4d13eSSimon Budig if (!tsdata->raw_buffer) { 65143c4d13eSSimon Budig error = -ENOMEM; 65243c4d13eSSimon Budig goto err_out; 65343c4d13eSSimon Budig } 65443c4d13eSSimon Budig } 65543c4d13eSSimon Budig 65643c4d13eSSimon Budig /* mode register is 0x3c when in the work mode */ 657*9dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03); 65843c4d13eSSimon Budig if (error) { 65943c4d13eSSimon Budig dev_err(&client->dev, 66043c4d13eSSimon Budig "failed to switch to factory mode, error %d\n", error); 66143c4d13eSSimon Budig goto err_out; 66243c4d13eSSimon Budig } 66343c4d13eSSimon Budig 66443c4d13eSSimon Budig tsdata->factory_mode = true; 66543c4d13eSSimon Budig do { 66643c4d13eSSimon Budig mdelay(EDT_SWITCH_MODE_DELAY); 66743c4d13eSSimon Budig /* mode register is 0x01 when in factory mode */ 668*9dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE, 669*9dfd9708SDario Binacchi &val); 670*9dfd9708SDario Binacchi if (!error && val == 0x03) 67143c4d13eSSimon Budig break; 67243c4d13eSSimon Budig } while (--retries > 0); 67343c4d13eSSimon Budig 67443c4d13eSSimon Budig if (retries == 0) { 67543c4d13eSSimon Budig dev_err(&client->dev, "not in factory mode after %dms.\n", 67643c4d13eSSimon Budig EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); 67743c4d13eSSimon Budig error = -EIO; 67843c4d13eSSimon Budig goto err_out; 67943c4d13eSSimon Budig } 68043c4d13eSSimon Budig 68143c4d13eSSimon Budig return 0; 68243c4d13eSSimon Budig 68343c4d13eSSimon Budig err_out: 68443c4d13eSSimon Budig kfree(tsdata->raw_buffer); 68543c4d13eSSimon Budig tsdata->raw_buffer = NULL; 68643c4d13eSSimon Budig tsdata->factory_mode = false; 68743c4d13eSSimon Budig enable_irq(client->irq); 68843c4d13eSSimon Budig 68943c4d13eSSimon Budig return error; 69043c4d13eSSimon Budig } 69143c4d13eSSimon Budig 69243c4d13eSSimon Budig static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) 69343c4d13eSSimon Budig { 69443c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 69543c4d13eSSimon Budig int retries = EDT_SWITCH_MODE_RETRIES; 696*9dfd9708SDario Binacchi unsigned int val; 69743c4d13eSSimon Budig int error; 69843c4d13eSSimon Budig 69943c4d13eSSimon Budig /* mode register is 0x01 when in the factory mode */ 700*9dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1); 70143c4d13eSSimon Budig if (error) { 70243c4d13eSSimon Budig dev_err(&client->dev, 70343c4d13eSSimon Budig "failed to switch to work mode, error: %d\n", error); 70443c4d13eSSimon Budig return error; 70543c4d13eSSimon Budig } 70643c4d13eSSimon Budig 70743c4d13eSSimon Budig tsdata->factory_mode = false; 70843c4d13eSSimon Budig 70943c4d13eSSimon Budig do { 71043c4d13eSSimon Budig mdelay(EDT_SWITCH_MODE_DELAY); 71143c4d13eSSimon Budig /* mode register is 0x01 when in factory mode */ 712*9dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val); 713*9dfd9708SDario Binacchi if (!error && val == 0x01) 71443c4d13eSSimon Budig break; 71543c4d13eSSimon Budig } while (--retries > 0); 71643c4d13eSSimon Budig 71743c4d13eSSimon Budig if (retries == 0) { 71843c4d13eSSimon Budig dev_err(&client->dev, "not in work mode after %dms.\n", 71943c4d13eSSimon Budig EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); 72043c4d13eSSimon Budig tsdata->factory_mode = true; 72143c4d13eSSimon Budig return -EIO; 72243c4d13eSSimon Budig } 72343c4d13eSSimon Budig 72443c4d13eSSimon Budig kfree(tsdata->raw_buffer); 72543c4d13eSSimon Budig tsdata->raw_buffer = NULL; 72643c4d13eSSimon Budig 727f4ee52f3SMarco Felsch edt_ft5x06_restore_reg_parameters(tsdata); 72843c4d13eSSimon Budig enable_irq(client->irq); 72943c4d13eSSimon Budig 73043c4d13eSSimon Budig return 0; 73143c4d13eSSimon Budig } 73243c4d13eSSimon Budig 73343c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode) 73443c4d13eSSimon Budig { 73543c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = data; 73643c4d13eSSimon Budig 73743c4d13eSSimon Budig *mode = tsdata->factory_mode; 73843c4d13eSSimon Budig 73943c4d13eSSimon Budig return 0; 74043c4d13eSSimon Budig }; 74143c4d13eSSimon Budig 74243c4d13eSSimon Budig static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) 74343c4d13eSSimon Budig { 74443c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = data; 74543c4d13eSSimon Budig int retval = 0; 74643c4d13eSSimon Budig 74743c4d13eSSimon Budig if (mode > 1) 74843c4d13eSSimon Budig return -ERANGE; 74943c4d13eSSimon Budig 75043c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 75143c4d13eSSimon Budig 75243c4d13eSSimon Budig if (mode != tsdata->factory_mode) { 75343c4d13eSSimon Budig retval = mode ? edt_ft5x06_factory_mode(tsdata) : 75443c4d13eSSimon Budig edt_ft5x06_work_mode(tsdata); 75543c4d13eSSimon Budig } 75643c4d13eSSimon Budig 75743c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 75843c4d13eSSimon Budig 75943c4d13eSSimon Budig return retval; 76043c4d13eSSimon Budig }; 76143c4d13eSSimon Budig 76243c4d13eSSimon Budig DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, 76343c4d13eSSimon Budig edt_ft5x06_debugfs_mode_set, "%llu\n"); 76443c4d13eSSimon Budig 76543c4d13eSSimon Budig static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, 766d19ec82cSDario Binacchi char __user *buf, size_t count, 767d19ec82cSDario Binacchi loff_t *off) 76843c4d13eSSimon Budig { 76943c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = file->private_data; 77043c4d13eSSimon Budig struct i2c_client *client = tsdata->client; 77143c4d13eSSimon Budig int retries = EDT_RAW_DATA_RETRIES; 772*9dfd9708SDario Binacchi unsigned int val; 773*9dfd9708SDario Binacchi int i, error; 77443c4d13eSSimon Budig size_t read = 0; 77543c4d13eSSimon Budig int colbytes; 77643c4d13eSSimon Budig u8 *rdbuf; 77743c4d13eSSimon Budig 77843c4d13eSSimon Budig if (*off < 0 || *off >= tsdata->raw_bufsize) 77943c4d13eSSimon Budig return 0; 78043c4d13eSSimon Budig 78143c4d13eSSimon Budig mutex_lock(&tsdata->mutex); 78243c4d13eSSimon Budig 78343c4d13eSSimon Budig if (!tsdata->factory_mode || !tsdata->raw_buffer) { 78443c4d13eSSimon Budig error = -EIO; 78543c4d13eSSimon Budig goto out; 78643c4d13eSSimon Budig } 78743c4d13eSSimon Budig 788*9dfd9708SDario Binacchi error = regmap_write(tsdata->regmap, 0x08, 0x01); 78943c4d13eSSimon Budig if (error) { 79024642661SDario Binacchi dev_err(&client->dev, 79143c4d13eSSimon Budig "failed to write 0x08 register, error %d\n", error); 79243c4d13eSSimon Budig goto out; 79343c4d13eSSimon Budig } 79443c4d13eSSimon Budig 79543c4d13eSSimon Budig do { 7960eeecf60SAniroop Mathur usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100); 797*9dfd9708SDario Binacchi error = regmap_read(tsdata->regmap, 0x08, &val); 798*9dfd9708SDario Binacchi if (error) { 79924642661SDario Binacchi dev_err(&client->dev, 800*9dfd9708SDario Binacchi "failed to read 0x08 register, error %d\n", 801*9dfd9708SDario Binacchi error); 80243c4d13eSSimon Budig goto out; 80343c4d13eSSimon Budig } 80443c4d13eSSimon Budig 805*9dfd9708SDario Binacchi if (val == 1) 806*9dfd9708SDario Binacchi break; 807*9dfd9708SDario Binacchi } while (--retries > 0); 808*9dfd9708SDario Binacchi 80943c4d13eSSimon Budig if (retries == 0) { 81024642661SDario Binacchi dev_err(&client->dev, 81143c4d13eSSimon Budig "timed out waiting for register to settle\n"); 81243c4d13eSSimon Budig error = -ETIMEDOUT; 81343c4d13eSSimon Budig goto out; 81443c4d13eSSimon Budig } 81543c4d13eSSimon Budig 81643c4d13eSSimon Budig rdbuf = tsdata->raw_buffer; 81743c4d13eSSimon Budig colbytes = tsdata->num_y * sizeof(u16); 81843c4d13eSSimon Budig 81943c4d13eSSimon Budig for (i = 0; i < tsdata->num_x; i++) { 820*9dfd9708SDario Binacchi rdbuf[0] = i; /* column index */ 821*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes); 82243c4d13eSSimon Budig if (error) 82343c4d13eSSimon Budig goto out; 82443c4d13eSSimon Budig 82543c4d13eSSimon Budig rdbuf += colbytes; 82643c4d13eSSimon Budig } 82743c4d13eSSimon Budig 82843c4d13eSSimon Budig read = min_t(size_t, count, tsdata->raw_bufsize - *off); 82935b1da4eSAxel Lin if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { 83035b1da4eSAxel Lin error = -EFAULT; 83135b1da4eSAxel Lin goto out; 83235b1da4eSAxel Lin } 83335b1da4eSAxel Lin 83443c4d13eSSimon Budig *off += read; 83543c4d13eSSimon Budig out: 83643c4d13eSSimon Budig mutex_unlock(&tsdata->mutex); 83743c4d13eSSimon Budig return error ?: read; 83843c4d13eSSimon Budig }; 83943c4d13eSSimon Budig 84043c4d13eSSimon Budig static const struct file_operations debugfs_raw_data_fops = { 841f6c0df6aSWei Yongjun .open = simple_open, 84243c4d13eSSimon Budig .read = edt_ft5x06_debugfs_raw_data_read, 84343c4d13eSSimon Budig }; 84443c4d13eSSimon Budig 84521d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 84643c4d13eSSimon Budig const char *debugfs_name) 84743c4d13eSSimon Budig { 84843c4d13eSSimon Budig tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); 84943c4d13eSSimon Budig 85043c4d13eSSimon Budig debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); 85143c4d13eSSimon Budig debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); 85243c4d13eSSimon Budig 85343c4d13eSSimon Budig debugfs_create_file("mode", S_IRUSR | S_IWUSR, 85443c4d13eSSimon Budig tsdata->debug_dir, tsdata, &debugfs_mode_fops); 85543c4d13eSSimon Budig debugfs_create_file("raw_data", S_IRUSR, 85643c4d13eSSimon Budig tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); 85743c4d13eSSimon Budig } 85843c4d13eSSimon Budig 85921d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 86043c4d13eSSimon Budig { 86143c4d13eSSimon Budig debugfs_remove_recursive(tsdata->debug_dir); 862a1d0fa77SGuenter Roeck kfree(tsdata->raw_buffer); 86343c4d13eSSimon Budig } 86443c4d13eSSimon Budig 86543c4d13eSSimon Budig #else 86643c4d13eSSimon Budig 86721d1611aSMarco Felsch static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) 86821d1611aSMarco Felsch { 86921d1611aSMarco Felsch return -ENOSYS; 87021d1611aSMarco Felsch } 87121d1611aSMarco Felsch 87221d1611aSMarco Felsch static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 87343c4d13eSSimon Budig const char *debugfs_name) 87443c4d13eSSimon Budig { 87543c4d13eSSimon Budig } 87643c4d13eSSimon Budig 87721d1611aSMarco Felsch static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 87843c4d13eSSimon Budig { 87943c4d13eSSimon Budig } 88043c4d13eSSimon Budig 88143c4d13eSSimon Budig #endif /* CONFIG_DEBUGFS */ 88243c4d13eSSimon Budig 8835298cc4cSBill Pemberton static int edt_ft5x06_ts_identify(struct i2c_client *client, 884480343dcSDario Binacchi struct edt_ft5x06_ts_data *tsdata) 88543c4d13eSSimon Budig { 88643c4d13eSSimon Budig u8 rdbuf[EDT_NAME_LEN]; 88743c4d13eSSimon Budig char *p; 88843c4d13eSSimon Budig int error; 889fd335ab0SLothar Waßmann char *model_name = tsdata->name; 890480343dcSDario Binacchi char *fw_version = tsdata->fw_version; 89143c4d13eSSimon Budig 892fd335ab0SLothar Waßmann /* see what we find if we assume it is a M06 * 893fd335ab0SLothar Waßmann * if we get less than EDT_NAME_LEN, we don't want 894fd335ab0SLothar Waßmann * to have garbage in there 895fd335ab0SLothar Waßmann */ 896fd335ab0SLothar Waßmann memset(rdbuf, 0, sizeof(rdbuf)); 897*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1); 89843c4d13eSSimon Budig if (error) 89943c4d13eSSimon Budig return error; 90043c4d13eSSimon Budig 901aed5d0eeSSimon Budig /* Probe content for something consistent. 902aed5d0eeSSimon Budig * M06 starts with a response byte, M12 gives the data directly. 903aed5d0eeSSimon Budig * M09/Generic does not provide model number information. 904fd335ab0SLothar Waßmann */ 905aed5d0eeSSimon Budig if (!strncasecmp(rdbuf + 1, "EP0", 3)) { 906169110c3SSimon Budig tsdata->version = EDT_M06; 907fd335ab0SLothar Waßmann 90843c4d13eSSimon Budig /* remove last '$' end marker */ 90943c4d13eSSimon Budig rdbuf[EDT_NAME_LEN - 1] = '\0'; 91043c4d13eSSimon Budig if (rdbuf[EDT_NAME_LEN - 2] == '$') 91143c4d13eSSimon Budig rdbuf[EDT_NAME_LEN - 2] = '\0'; 91243c4d13eSSimon Budig 91343c4d13eSSimon Budig /* look for Model/Version separator */ 91443c4d13eSSimon Budig p = strchr(rdbuf, '*'); 91543c4d13eSSimon Budig if (p) 91643c4d13eSSimon Budig *p++ = '\0'; 917a9f08ad7SWolfram Sang strscpy(model_name, rdbuf + 1, EDT_NAME_LEN); 918a9f08ad7SWolfram Sang strscpy(fw_version, p ? p : "", EDT_NAME_LEN); 919*9dfd9708SDario Binacchi 920*9dfd9708SDario Binacchi regmap_exit(tsdata->regmap); 921*9dfd9708SDario Binacchi tsdata->regmap = regmap_init_i2c(client, 922*9dfd9708SDario Binacchi &edt_M06_i2c_regmap_config); 923*9dfd9708SDario Binacchi if (IS_ERR(tsdata->regmap)) { 924*9dfd9708SDario Binacchi dev_err(&client->dev, "regmap allocation failed\n"); 925*9dfd9708SDario Binacchi return PTR_ERR(tsdata->regmap); 926*9dfd9708SDario Binacchi } 927aed5d0eeSSimon Budig } else if (!strncasecmp(rdbuf, "EP0", 3)) { 928aed5d0eeSSimon Budig tsdata->version = EDT_M12; 929aed5d0eeSSimon Budig 930aed5d0eeSSimon Budig /* remove last '$' end marker */ 931aed5d0eeSSimon Budig rdbuf[EDT_NAME_LEN - 2] = '\0'; 932aed5d0eeSSimon Budig if (rdbuf[EDT_NAME_LEN - 3] == '$') 933aed5d0eeSSimon Budig rdbuf[EDT_NAME_LEN - 3] = '\0'; 934aed5d0eeSSimon Budig 935aed5d0eeSSimon Budig /* look for Model/Version separator */ 936aed5d0eeSSimon Budig p = strchr(rdbuf, '*'); 937aed5d0eeSSimon Budig if (p) 938aed5d0eeSSimon Budig *p++ = '\0'; 939a9f08ad7SWolfram Sang strscpy(model_name, rdbuf, EDT_NAME_LEN); 940a9f08ad7SWolfram Sang strscpy(fw_version, p ? p : "", EDT_NAME_LEN); 941fd335ab0SLothar Waßmann } else { 942aed5d0eeSSimon Budig /* If it is not an EDT M06/M12 touchscreen, then the model 943169110c3SSimon Budig * detection is a bit hairy. The different ft5x06 94462c5e854SDario Binacchi * firmwares around don't reliably implement the 945169110c3SSimon Budig * identification registers. Well, we'll take a shot. 946169110c3SSimon Budig * 947169110c3SSimon Budig * The main difference between generic focaltec based 948169110c3SSimon Budig * touches and EDT M09 is that we know how to retrieve 949169110c3SSimon Budig * the max coordinates for the latter. 950169110c3SSimon Budig */ 951169110c3SSimon Budig tsdata->version = GENERIC_FT; 952fd335ab0SLothar Waßmann 953*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2); 954fd335ab0SLothar Waßmann if (error) 955fd335ab0SLothar Waßmann return error; 956fd335ab0SLothar Waßmann 957a9f08ad7SWolfram Sang strscpy(fw_version, rdbuf, 2); 958fd335ab0SLothar Waßmann 959*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1); 960fd335ab0SLothar Waßmann if (error) 961fd335ab0SLothar Waßmann return error; 962fd335ab0SLothar Waßmann 963169110c3SSimon Budig /* This "model identification" is not exact. Unfortunately 964169110c3SSimon Budig * not all firmwares for the ft5x06 put useful values in 965169110c3SSimon Budig * the identification registers. 966169110c3SSimon Budig */ 967169110c3SSimon Budig switch (rdbuf[0]) { 968146ea9b6SOliver Graute case 0x11: /* EDT EP0110M09 */ 969169110c3SSimon Budig case 0x35: /* EDT EP0350M09 */ 970169110c3SSimon Budig case 0x43: /* EDT EP0430M09 */ 971169110c3SSimon Budig case 0x50: /* EDT EP0500M09 */ 972169110c3SSimon Budig case 0x57: /* EDT EP0570M09 */ 973169110c3SSimon Budig case 0x70: /* EDT EP0700M09 */ 974169110c3SSimon Budig tsdata->version = EDT_M09; 975fd335ab0SLothar Waßmann snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", 976fd335ab0SLothar Waßmann rdbuf[0] >> 4, rdbuf[0] & 0x0F); 977169110c3SSimon Budig break; 978169110c3SSimon Budig case 0xa1: /* EDT EP1010ML00 */ 979169110c3SSimon Budig tsdata->version = EDT_M09; 980169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", 981169110c3SSimon Budig rdbuf[0] >> 4, rdbuf[0] & 0x0F); 982169110c3SSimon Budig break; 983169110c3SSimon Budig case 0x5a: /* Solomon Goldentek Display */ 984169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); 985169110c3SSimon Budig break; 986a2f39dacSMarco Felsch case 0x59: /* Evervision Display with FT5xx6 TS */ 987a2f39dacSMarco Felsch tsdata->version = EV_FT; 988*9dfd9708SDario Binacchi error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1); 989a2f39dacSMarco Felsch if (error) 990a2f39dacSMarco Felsch return error; 991a9f08ad7SWolfram Sang strscpy(fw_version, rdbuf, 1); 992a2f39dacSMarco Felsch snprintf(model_name, EDT_NAME_LEN, 993a2f39dacSMarco Felsch "EVERVISION-FT5726NEi"); 994a2f39dacSMarco Felsch break; 995169110c3SSimon Budig default: 996169110c3SSimon Budig snprintf(model_name, EDT_NAME_LEN, 997169110c3SSimon Budig "generic ft5x06 (%02x)", 998169110c3SSimon Budig rdbuf[0]); 999169110c3SSimon Budig break; 1000169110c3SSimon Budig } 1001fd335ab0SLothar Waßmann } 100243c4d13eSSimon Budig 100343c4d13eSSimon Budig return 0; 100443c4d13eSSimon Budig } 100543c4d13eSSimon Budig 10062e23b7a9SDmitry Torokhov static void edt_ft5x06_ts_get_defaults(struct device *dev, 1007dac90dc2SLothar Waßmann struct edt_ft5x06_ts_data *tsdata) 1008dac90dc2SLothar Waßmann { 1009fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 1010*9dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 10112e23b7a9SDmitry Torokhov u32 val; 10122e23b7a9SDmitry Torokhov int error; 1013fd335ab0SLothar Waßmann 10142e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "threshold", &val); 1015dc262dfaSPhilipp Zabel if (!error) { 1016*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_threshold, val); 1017dc262dfaSPhilipp Zabel tsdata->threshold = val; 1018dc262dfaSPhilipp Zabel } 10192e23b7a9SDmitry Torokhov 10202e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "gain", &val); 1021dc262dfaSPhilipp Zabel if (!error) { 1022*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_gain, val); 1023dc262dfaSPhilipp Zabel tsdata->gain = val; 1024dc262dfaSPhilipp Zabel } 10252e23b7a9SDmitry Torokhov 10262e23b7a9SDmitry Torokhov error = device_property_read_u32(dev, "offset", &val); 1027dc262dfaSPhilipp Zabel if (!error) { 1028255cdaf7SMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 1029*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset, val); 1030dc262dfaSPhilipp Zabel tsdata->offset = val; 1031dc262dfaSPhilipp Zabel } 1032b6eba860SMarco Felsch 1033b6eba860SMarco Felsch error = device_property_read_u32(dev, "offset-x", &val); 1034b6eba860SMarco Felsch if (!error) { 1035255cdaf7SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 1036*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_x, val); 1037b6eba860SMarco Felsch tsdata->offset_x = val; 1038b6eba860SMarco Felsch } 1039b6eba860SMarco Felsch 1040b6eba860SMarco Felsch error = device_property_read_u32(dev, "offset-y", &val); 1041b6eba860SMarco Felsch if (!error) { 1042255cdaf7SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 1043*9dfd9708SDario Binacchi regmap_write(regmap, reg_addr->reg_offset_y, val); 1044b6eba860SMarco Felsch tsdata->offset_y = val; 1045b6eba860SMarco Felsch } 1046dac90dc2SLothar Waßmann } 1047dac90dc2SLothar Waßmann 104803161a95SDmitry Torokhov static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) 104943c4d13eSSimon Budig { 1050fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 1051*9dfd9708SDario Binacchi struct regmap *regmap = tsdata->regmap; 1052*9dfd9708SDario Binacchi unsigned int val; 1053fd335ab0SLothar Waßmann 1054*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold); 1055*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain); 1056a2f39dacSMarco Felsch if (reg_addr->reg_offset != NO_REGISTER) 1057*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset); 1058b6eba860SMarco Felsch if (reg_addr->reg_offset_x != NO_REGISTER) 1059*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x); 1060b6eba860SMarco Felsch if (reg_addr->reg_offset_y != NO_REGISTER) 1061*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y); 1062fd335ab0SLothar Waßmann if (reg_addr->reg_report_rate != NO_REGISTER) 1063*9dfd9708SDario Binacchi regmap_read(regmap, reg_addr->reg_report_rate, 1064*9dfd9708SDario Binacchi &tsdata->report_rate); 106503161a95SDmitry Torokhov tsdata->num_x = EDT_DEFAULT_NUM_X; 1066*9dfd9708SDario Binacchi if (reg_addr->reg_num_x != NO_REGISTER) { 1067*9dfd9708SDario Binacchi if (!regmap_read(regmap, reg_addr->reg_num_x, &val)) 1068*9dfd9708SDario Binacchi tsdata->num_x = val; 1069*9dfd9708SDario Binacchi } 107003161a95SDmitry Torokhov tsdata->num_y = EDT_DEFAULT_NUM_Y; 1071*9dfd9708SDario Binacchi if (reg_addr->reg_num_y != NO_REGISTER) { 1072*9dfd9708SDario Binacchi if (!regmap_read(regmap, reg_addr->reg_num_y, &val)) 1073*9dfd9708SDario Binacchi tsdata->num_y = val; 1074*9dfd9708SDario Binacchi } 1075fd335ab0SLothar Waßmann } 1076fd335ab0SLothar Waßmann 107703161a95SDmitry Torokhov static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) 1078fd335ab0SLothar Waßmann { 1079fd335ab0SLothar Waßmann struct edt_reg_addr *reg_addr = &tsdata->reg_addr; 1080fd335ab0SLothar Waßmann 1081fd335ab0SLothar Waßmann switch (tsdata->version) { 1082169110c3SSimon Budig case EDT_M06: 1083fd335ab0SLothar Waßmann reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; 1084fd335ab0SLothar Waßmann reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; 1085fd335ab0SLothar Waßmann reg_addr->reg_gain = WORK_REGISTER_GAIN; 1086fd335ab0SLothar Waßmann reg_addr->reg_offset = WORK_REGISTER_OFFSET; 1087b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1088b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 1089fd335ab0SLothar Waßmann reg_addr->reg_num_x = WORK_REGISTER_NUM_X; 1090fd335ab0SLothar Waßmann reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; 1091fd335ab0SLothar Waßmann break; 1092fd335ab0SLothar Waßmann 1093169110c3SSimon Budig case EDT_M09: 1094aed5d0eeSSimon Budig case EDT_M12: 1095fd335ab0SLothar Waßmann reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; 109623ea98f4SDario Binacchi reg_addr->reg_report_rate = tsdata->version == EDT_M12 ? 109723ea98f4SDario Binacchi M12_REGISTER_REPORT_RATE : NO_REGISTER; 1098fd335ab0SLothar Waßmann reg_addr->reg_gain = M09_REGISTER_GAIN; 1099fd335ab0SLothar Waßmann reg_addr->reg_offset = M09_REGISTER_OFFSET; 1100b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1101b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 1102fd335ab0SLothar Waßmann reg_addr->reg_num_x = M09_REGISTER_NUM_X; 1103fd335ab0SLothar Waßmann reg_addr->reg_num_y = M09_REGISTER_NUM_Y; 1104fd335ab0SLothar Waßmann break; 1105169110c3SSimon Budig 1106a2f39dacSMarco Felsch case EV_FT: 1107a2f39dacSMarco Felsch reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; 110803161a95SDmitry Torokhov reg_addr->reg_report_rate = NO_REGISTER; 1109a2f39dacSMarco Felsch reg_addr->reg_gain = EV_REGISTER_GAIN; 1110a2f39dacSMarco Felsch reg_addr->reg_offset = NO_REGISTER; 1111b6eba860SMarco Felsch reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; 1112b6eba860SMarco Felsch reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; 1113a2f39dacSMarco Felsch reg_addr->reg_num_x = NO_REGISTER; 1114a2f39dacSMarco Felsch reg_addr->reg_num_y = NO_REGISTER; 1115a2f39dacSMarco Felsch break; 1116a2f39dacSMarco Felsch 1117169110c3SSimon Budig case GENERIC_FT: 1118169110c3SSimon Budig /* this is a guesswork */ 1119169110c3SSimon Budig reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; 112003161a95SDmitry Torokhov reg_addr->reg_report_rate = NO_REGISTER; 1121169110c3SSimon Budig reg_addr->reg_gain = M09_REGISTER_GAIN; 1122169110c3SSimon Budig reg_addr->reg_offset = M09_REGISTER_OFFSET; 1123b6eba860SMarco Felsch reg_addr->reg_offset_x = NO_REGISTER; 1124b6eba860SMarco Felsch reg_addr->reg_offset_y = NO_REGISTER; 112503161a95SDmitry Torokhov reg_addr->reg_num_x = NO_REGISTER; 112603161a95SDmitry Torokhov reg_addr->reg_num_y = NO_REGISTER; 1127169110c3SSimon Budig break; 1128fd335ab0SLothar Waßmann } 112943c4d13eSSimon Budig } 113043c4d13eSSimon Budig 1131df4c40f4SStephan Gerhold static void edt_ft5x06_disable_regulators(void *arg) 11327448bfecSMylène Josserand { 11337448bfecSMylène Josserand struct edt_ft5x06_ts_data *data = arg; 11347448bfecSMylène Josserand 11357448bfecSMylène Josserand regulator_disable(data->vcc); 1136df4c40f4SStephan Gerhold regulator_disable(data->iovcc); 11377448bfecSMylène Josserand } 11387448bfecSMylène Josserand 1139e7c31218SUwe Kleine-König static int edt_ft5x06_ts_probe(struct i2c_client *client) 114043c4d13eSSimon Budig { 1141e7c31218SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client); 1142b1d2a3ecSFranklin S Cooper Jr const struct edt_i2c_chip_data *chip_data; 114343c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata; 1144*9dfd9708SDario Binacchi unsigned int val; 114543c4d13eSSimon Budig struct input_dev *input; 1146f0bef75cSDmitry Torokhov unsigned long irq_flags; 114743c4d13eSSimon Budig int error; 11485bcee83aSDario Binacchi u32 report_rate; 114943c4d13eSSimon Budig 115043c4d13eSSimon Budig dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); 115143c4d13eSSimon Budig 115202300bd6SLothar Waßmann tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); 115302300bd6SLothar Waßmann if (!tsdata) { 115443c4d13eSSimon Budig dev_err(&client->dev, "failed to allocate driver data.\n"); 115502300bd6SLothar Waßmann return -ENOMEM; 115602300bd6SLothar Waßmann } 115702300bd6SLothar Waßmann 1158*9dfd9708SDario Binacchi tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); 1159*9dfd9708SDario Binacchi if (IS_ERR(tsdata->regmap)) { 1160*9dfd9708SDario Binacchi dev_err(&client->dev, "regmap allocation failed\n"); 1161*9dfd9708SDario Binacchi return PTR_ERR(tsdata->regmap); 1162*9dfd9708SDario Binacchi } 1163*9dfd9708SDario Binacchi 1164fc226eb2SAndy Shevchenko chip_data = device_get_match_data(&client->dev); 1165b1d2a3ecSFranklin S Cooper Jr if (!chip_data) 1166b1d2a3ecSFranklin S Cooper Jr chip_data = (const struct edt_i2c_chip_data *)id->driver_data; 1167b1d2a3ecSFranklin S Cooper Jr if (!chip_data || !chip_data->max_support_points) { 1168b1d2a3ecSFranklin S Cooper Jr dev_err(&client->dev, "invalid or missing chip data\n"); 1169b1d2a3ecSFranklin S Cooper Jr return -EINVAL; 1170b1d2a3ecSFranklin S Cooper Jr } 1171b1d2a3ecSFranklin S Cooper Jr 1172b1d2a3ecSFranklin S Cooper Jr tsdata->max_support_points = chip_data->max_support_points; 1173b1d2a3ecSFranklin S Cooper Jr 11747448bfecSMylène Josserand tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); 11757448bfecSMylène Josserand if (IS_ERR(tsdata->vcc)) { 11767448bfecSMylène Josserand error = PTR_ERR(tsdata->vcc); 11777448bfecSMylène Josserand if (error != -EPROBE_DEFER) 11787448bfecSMylène Josserand dev_err(&client->dev, 11797448bfecSMylène Josserand "failed to request regulator: %d\n", error); 11807448bfecSMylène Josserand return error; 11817448bfecSMylène Josserand } 11827448bfecSMylène Josserand 1183df4c40f4SStephan Gerhold tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); 1184df4c40f4SStephan Gerhold if (IS_ERR(tsdata->iovcc)) { 1185df4c40f4SStephan Gerhold error = PTR_ERR(tsdata->iovcc); 1186df4c40f4SStephan Gerhold if (error != -EPROBE_DEFER) 1187df4c40f4SStephan Gerhold dev_err(&client->dev, 1188df4c40f4SStephan Gerhold "failed to request iovcc regulator: %d\n", error); 1189df4c40f4SStephan Gerhold return error; 1190df4c40f4SStephan Gerhold } 1191df4c40f4SStephan Gerhold 1192df4c40f4SStephan Gerhold error = regulator_enable(tsdata->iovcc); 1193df4c40f4SStephan Gerhold if (error < 0) { 1194df4c40f4SStephan Gerhold dev_err(&client->dev, "failed to enable iovcc: %d\n", error); 1195df4c40f4SStephan Gerhold return error; 1196df4c40f4SStephan Gerhold } 1197df4c40f4SStephan Gerhold 1198df4c40f4SStephan Gerhold /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ 1199df4c40f4SStephan Gerhold usleep_range(10, 100); 1200df4c40f4SStephan Gerhold 12017448bfecSMylène Josserand error = regulator_enable(tsdata->vcc); 12027448bfecSMylène Josserand if (error < 0) { 12037448bfecSMylène Josserand dev_err(&client->dev, "failed to enable vcc: %d\n", error); 1204df4c40f4SStephan Gerhold regulator_disable(tsdata->iovcc); 12057448bfecSMylène Josserand return error; 12067448bfecSMylène Josserand } 12077448bfecSMylène Josserand 12087448bfecSMylène Josserand error = devm_add_action_or_reset(&client->dev, 1209df4c40f4SStephan Gerhold edt_ft5x06_disable_regulators, 12107448bfecSMylène Josserand tsdata); 12117448bfecSMylène Josserand if (error) 12127448bfecSMylène Josserand return error; 12137448bfecSMylène Josserand 121413c23cd1SFranklin S Cooper Jr tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev, 121513c23cd1SFranklin S Cooper Jr "reset", GPIOD_OUT_HIGH); 121613c23cd1SFranklin S Cooper Jr if (IS_ERR(tsdata->reset_gpio)) { 121713c23cd1SFranklin S Cooper Jr error = PTR_ERR(tsdata->reset_gpio); 1218dac90dc2SLothar Waßmann dev_err(&client->dev, 121913c23cd1SFranklin S Cooper Jr "Failed to request GPIO reset pin, error %d\n", error); 1220dac90dc2SLothar Waßmann return error; 1221dac90dc2SLothar Waßmann } 1222dac90dc2SLothar Waßmann 122313c23cd1SFranklin S Cooper Jr tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev, 122413c23cd1SFranklin S Cooper Jr "wake", GPIOD_OUT_LOW); 122513c23cd1SFranklin S Cooper Jr if (IS_ERR(tsdata->wake_gpio)) { 122613c23cd1SFranklin S Cooper Jr error = PTR_ERR(tsdata->wake_gpio); 1227dac90dc2SLothar Waßmann dev_err(&client->dev, 122813c23cd1SFranklin S Cooper Jr "Failed to request GPIO wake pin, error %d\n", error); 1229dac90dc2SLothar Waßmann return error; 1230dac90dc2SLothar Waßmann } 123113c23cd1SFranklin S Cooper Jr 123221d1611aSMarco Felsch /* 123321d1611aSMarco Felsch * Check which sleep modes we can support. Power-off requieres the 123421d1611aSMarco Felsch * reset-pin to ensure correct power-down/power-up behaviour. Start with 123521d1611aSMarco Felsch * the EDT_PMODE_POWEROFF test since this is the deepest possible sleep 123621d1611aSMarco Felsch * mode. 123721d1611aSMarco Felsch */ 123821d1611aSMarco Felsch if (tsdata->reset_gpio) 123921d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_POWEROFF; 124021d1611aSMarco Felsch else if (tsdata->wake_gpio) 124121d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_HIBERNATE; 124221d1611aSMarco Felsch else 124321d1611aSMarco Felsch tsdata->suspend_mode = EDT_PMODE_NOT_SUPPORTED; 124421d1611aSMarco Felsch 124513c23cd1SFranklin S Cooper Jr if (tsdata->wake_gpio) { 124613c23cd1SFranklin S Cooper Jr usleep_range(5000, 6000); 124713c23cd1SFranklin S Cooper Jr gpiod_set_value_cansleep(tsdata->wake_gpio, 1); 124813c23cd1SFranklin S Cooper Jr } 124913c23cd1SFranklin S Cooper Jr 125013c23cd1SFranklin S Cooper Jr if (tsdata->reset_gpio) { 125113c23cd1SFranklin S Cooper Jr usleep_range(5000, 6000); 125213c23cd1SFranklin S Cooper Jr gpiod_set_value_cansleep(tsdata->reset_gpio, 0); 125313c23cd1SFranklin S Cooper Jr msleep(300); 1254dac90dc2SLothar Waßmann } 1255dac90dc2SLothar Waßmann 125602300bd6SLothar Waßmann input = devm_input_allocate_device(&client->dev); 125702300bd6SLothar Waßmann if (!input) { 125802300bd6SLothar Waßmann dev_err(&client->dev, "failed to allocate input device.\n"); 125902300bd6SLothar Waßmann return -ENOMEM; 126043c4d13eSSimon Budig } 126143c4d13eSSimon Budig 126243c4d13eSSimon Budig mutex_init(&tsdata->mutex); 126343c4d13eSSimon Budig tsdata->client = client; 126443c4d13eSSimon Budig tsdata->input = input; 126543c4d13eSSimon Budig tsdata->factory_mode = false; 1266*9dfd9708SDario Binacchi i2c_set_clientdata(client, tsdata); 126743c4d13eSSimon Budig 1268480343dcSDario Binacchi error = edt_ft5x06_ts_identify(client, tsdata); 126943c4d13eSSimon Budig if (error) { 127043c4d13eSSimon Budig dev_err(&client->dev, "touchscreen probe failed\n"); 127102300bd6SLothar Waßmann return error; 127243c4d13eSSimon Budig } 127343c4d13eSSimon Budig 1274e112324cSPhilipp Zabel /* 1275e112324cSPhilipp Zabel * Dummy read access. EP0700MLP1 returns bogus data on the first 1276e112324cSPhilipp Zabel * register read access and ignores writes. 1277e112324cSPhilipp Zabel */ 1278*9dfd9708SDario Binacchi regmap_read(tsdata->regmap, 0x00, &val); 1279e112324cSPhilipp Zabel 1280fd335ab0SLothar Waßmann edt_ft5x06_ts_set_regs(tsdata); 12812e23b7a9SDmitry Torokhov edt_ft5x06_ts_get_defaults(&client->dev, tsdata); 128243c4d13eSSimon Budig edt_ft5x06_ts_get_parameters(tsdata); 128343c4d13eSSimon Budig 12845bcee83aSDario Binacchi if (tsdata->reg_addr.reg_report_rate != NO_REGISTER && 12855bcee83aSDario Binacchi !device_property_read_u32(&client->dev, 12865bcee83aSDario Binacchi "report-rate-hz", &report_rate)) { 12875bcee83aSDario Binacchi if (tsdata->version == EDT_M06) 12885bcee83aSDario Binacchi tsdata->report_rate = clamp_val(report_rate, 30, 140); 12895bcee83aSDario Binacchi else 12905bcee83aSDario Binacchi tsdata->report_rate = clamp_val(report_rate, 1, 255); 12915bcee83aSDario Binacchi 12925bcee83aSDario Binacchi if (report_rate != tsdata->report_rate) 12935bcee83aSDario Binacchi dev_warn(&client->dev, 12945bcee83aSDario Binacchi "report-rate %dHz is unsupported, use %dHz\n", 12955bcee83aSDario Binacchi report_rate, tsdata->report_rate); 12965bcee83aSDario Binacchi 12975bcee83aSDario Binacchi if (tsdata->version == EDT_M06) 12985bcee83aSDario Binacchi tsdata->report_rate /= 10; 12995bcee83aSDario Binacchi 1300*9dfd9708SDario Binacchi regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate, 13015bcee83aSDario Binacchi tsdata->report_rate); 13025bcee83aSDario Binacchi } 13035bcee83aSDario Binacchi 130443c4d13eSSimon Budig dev_dbg(&client->dev, 130543c4d13eSSimon Budig "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", 1306480343dcSDario Binacchi tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y); 130743c4d13eSSimon Budig 130843c4d13eSSimon Budig input->name = tsdata->name; 130943c4d13eSSimon Budig input->id.bustype = BUS_I2C; 131043c4d13eSSimon Budig input->dev.parent = &client->dev; 131143c4d13eSSimon Budig 131243c4d13eSSimon Budig input_set_abs_params(input, ABS_MT_POSITION_X, 131343c4d13eSSimon Budig 0, tsdata->num_x * 64 - 1, 0, 0); 131443c4d13eSSimon Budig input_set_abs_params(input, ABS_MT_POSITION_Y, 131543c4d13eSSimon Budig 0, tsdata->num_y * 64 - 1, 0, 0); 13162c005598SMaxime Ripard 1317ad368eb2SHans de Goede touchscreen_parse_properties(input, true, &tsdata->prop); 13182c005598SMaxime Ripard 1319b1d2a3ecSFranklin S Cooper Jr error = input_mt_init_slots(input, tsdata->max_support_points, 1320b1d2a3ecSFranklin S Cooper Jr INPUT_MT_DIRECT); 132143c4d13eSSimon Budig if (error) { 132243c4d13eSSimon Budig dev_err(&client->dev, "Unable to init MT slots.\n"); 132302300bd6SLothar Waßmann return error; 132443c4d13eSSimon Budig } 132543c4d13eSSimon Budig 1326f0bef75cSDmitry Torokhov irq_flags = irq_get_trigger_type(client->irq); 1327f0bef75cSDmitry Torokhov if (irq_flags == IRQF_TRIGGER_NONE) 1328f0bef75cSDmitry Torokhov irq_flags = IRQF_TRIGGER_FALLING; 1329f0bef75cSDmitry Torokhov irq_flags |= IRQF_ONESHOT; 1330f0bef75cSDmitry Torokhov 1331f0bef75cSDmitry Torokhov error = devm_request_threaded_irq(&client->dev, client->irq, 1332f0bef75cSDmitry Torokhov NULL, edt_ft5x06_ts_isr, irq_flags, 133343c4d13eSSimon Budig client->name, tsdata); 133443c4d13eSSimon Budig if (error) { 133543c4d13eSSimon Budig dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); 133602300bd6SLothar Waßmann return error; 133743c4d13eSSimon Budig } 133843c4d13eSSimon Budig 1339e3adf559SAndi Shyti error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); 134043c4d13eSSimon Budig if (error) 134102300bd6SLothar Waßmann return error; 134243c4d13eSSimon Budig 134343c4d13eSSimon Budig error = input_register_device(input); 1344dac90dc2SLothar Waßmann if (error) 1345e3adf559SAndi Shyti return error; 134643c4d13eSSimon Budig 134743c4d13eSSimon Budig edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); 134843c4d13eSSimon Budig 134943c4d13eSSimon Budig dev_dbg(&client->dev, 1350dac90dc2SLothar Waßmann "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", 13518b58cc36SFranklin S Cooper Jr client->irq, 13528b58cc36SFranklin S Cooper Jr tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, 13538b58cc36SFranklin S Cooper Jr tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); 135443c4d13eSSimon Budig 135543c4d13eSSimon Budig return 0; 135643c4d13eSSimon Budig } 135743c4d13eSSimon Budig 1358ed5c2f5fSUwe Kleine-König static void edt_ft5x06_ts_remove(struct i2c_client *client) 135943c4d13eSSimon Budig { 136043c4d13eSSimon Budig struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 136143c4d13eSSimon Budig 136243c4d13eSSimon Budig edt_ft5x06_ts_teardown_debugfs(tsdata); 1363*9dfd9708SDario Binacchi regmap_exit(tsdata->regmap); 136443c4d13eSSimon Budig } 136543c4d13eSSimon Budig 13666e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_suspend(struct device *dev) 136721d1611aSMarco Felsch { 136821d1611aSMarco Felsch struct i2c_client *client = to_i2c_client(dev); 136921d1611aSMarco Felsch struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 137021d1611aSMarco Felsch struct gpio_desc *reset_gpio = tsdata->reset_gpio; 137121d1611aSMarco Felsch int ret; 137221d1611aSMarco Felsch 137321d1611aSMarco Felsch if (device_may_wakeup(dev)) 137421d1611aSMarco Felsch return 0; 137521d1611aSMarco Felsch 137621d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED) 137721d1611aSMarco Felsch return 0; 137821d1611aSMarco Felsch 137921d1611aSMarco Felsch /* Enter hibernate mode. */ 1380*9dfd9708SDario Binacchi ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE, 138121d1611aSMarco Felsch PMOD_REGISTER_HIBERNATE); 138221d1611aSMarco Felsch if (ret) 138321d1611aSMarco Felsch dev_warn(dev, "Failed to set hibernate mode\n"); 138421d1611aSMarco Felsch 138521d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_HIBERNATE) 138621d1611aSMarco Felsch return 0; 138721d1611aSMarco Felsch 138821d1611aSMarco Felsch /* 138921d1611aSMarco Felsch * Power-off according the datasheet. Cut the power may leaf the irq 139021d1611aSMarco Felsch * line in an undefined state depending on the host pull resistor 139121d1611aSMarco Felsch * settings. Disable the irq to avoid adjusting each host till the 139221d1611aSMarco Felsch * device is back in a full functional state. 139321d1611aSMarco Felsch */ 139421d1611aSMarco Felsch disable_irq(tsdata->client->irq); 139521d1611aSMarco Felsch 139621d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 1); 139721d1611aSMarco Felsch usleep_range(1000, 2000); 139821d1611aSMarco Felsch 139921d1611aSMarco Felsch ret = regulator_disable(tsdata->vcc); 140021d1611aSMarco Felsch if (ret) 140121d1611aSMarco Felsch dev_warn(dev, "Failed to disable vcc\n"); 1402df4c40f4SStephan Gerhold ret = regulator_disable(tsdata->iovcc); 1403df4c40f4SStephan Gerhold if (ret) 1404df4c40f4SStephan Gerhold dev_warn(dev, "Failed to disable iovcc\n"); 140521d1611aSMarco Felsch 140621d1611aSMarco Felsch return 0; 140721d1611aSMarco Felsch } 140821d1611aSMarco Felsch 14096e6ebfc5SJonathan Cameron static int edt_ft5x06_ts_resume(struct device *dev) 141021d1611aSMarco Felsch { 141121d1611aSMarco Felsch struct i2c_client *client = to_i2c_client(dev); 141221d1611aSMarco Felsch struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); 141321d1611aSMarco Felsch int ret = 0; 141421d1611aSMarco Felsch 141521d1611aSMarco Felsch if (device_may_wakeup(dev)) 141621d1611aSMarco Felsch return 0; 141721d1611aSMarco Felsch 141821d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED) 141921d1611aSMarco Felsch return 0; 142021d1611aSMarco Felsch 142121d1611aSMarco Felsch if (tsdata->suspend_mode == EDT_PMODE_POWEROFF) { 142221d1611aSMarco Felsch struct gpio_desc *reset_gpio = tsdata->reset_gpio; 142321d1611aSMarco Felsch 142421d1611aSMarco Felsch /* 142521d1611aSMarco Felsch * We can't check if the regulator is a dummy or a real 142621d1611aSMarco Felsch * regulator. So we need to specify the 5ms reset time (T_rst) 142721d1611aSMarco Felsch * here instead of the 100us T_rtp time. We also need to wait 142821d1611aSMarco Felsch * 300ms in case it was a real supply and the power was cutted 142921d1611aSMarco Felsch * of. Toggle the reset pin is also a way to exit the hibernate 143021d1611aSMarco Felsch * mode. 143121d1611aSMarco Felsch */ 143221d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 1); 143321d1611aSMarco Felsch usleep_range(5000, 6000); 143421d1611aSMarco Felsch 1435df4c40f4SStephan Gerhold ret = regulator_enable(tsdata->iovcc); 1436df4c40f4SStephan Gerhold if (ret) { 1437df4c40f4SStephan Gerhold dev_err(dev, "Failed to enable iovcc\n"); 1438df4c40f4SStephan Gerhold return ret; 1439df4c40f4SStephan Gerhold } 1440df4c40f4SStephan Gerhold 1441df4c40f4SStephan Gerhold /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ 1442df4c40f4SStephan Gerhold usleep_range(10, 100); 1443df4c40f4SStephan Gerhold 144421d1611aSMarco Felsch ret = regulator_enable(tsdata->vcc); 144521d1611aSMarco Felsch if (ret) { 144621d1611aSMarco Felsch dev_err(dev, "Failed to enable vcc\n"); 1447df4c40f4SStephan Gerhold regulator_disable(tsdata->iovcc); 144821d1611aSMarco Felsch return ret; 144921d1611aSMarco Felsch } 145021d1611aSMarco Felsch 145121d1611aSMarco Felsch usleep_range(1000, 2000); 145221d1611aSMarco Felsch gpiod_set_value_cansleep(reset_gpio, 0); 145321d1611aSMarco Felsch msleep(300); 145421d1611aSMarco Felsch 145521d1611aSMarco Felsch edt_ft5x06_restore_reg_parameters(tsdata); 145621d1611aSMarco Felsch enable_irq(tsdata->client->irq); 145721d1611aSMarco Felsch 145821d1611aSMarco Felsch if (tsdata->factory_mode) 145921d1611aSMarco Felsch ret = edt_ft5x06_factory_mode(tsdata); 146021d1611aSMarco Felsch } else { 146121d1611aSMarco Felsch struct gpio_desc *wake_gpio = tsdata->wake_gpio; 146221d1611aSMarco Felsch 146321d1611aSMarco Felsch gpiod_set_value_cansleep(wake_gpio, 0); 146421d1611aSMarco Felsch usleep_range(5000, 6000); 146521d1611aSMarco Felsch gpiod_set_value_cansleep(wake_gpio, 1); 146621d1611aSMarco Felsch } 146721d1611aSMarco Felsch 146821d1611aSMarco Felsch return ret; 146921d1611aSMarco Felsch } 147021d1611aSMarco Felsch 14716e6ebfc5SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, 147221d1611aSMarco Felsch edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); 147321d1611aSMarco Felsch 1474b1d2a3ecSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5x06_data = { 1475b1d2a3ecSFranklin S Cooper Jr .max_support_points = 5, 1476b1d2a3ecSFranklin S Cooper Jr }; 1477b1d2a3ecSFranklin S Cooper Jr 1478af33e0adSFranklin S Cooper Jr static const struct edt_i2c_chip_data edt_ft5506_data = { 1479af33e0adSFranklin S Cooper Jr .max_support_points = 10, 1480af33e0adSFranklin S Cooper Jr }; 1481af33e0adSFranklin S Cooper Jr 1482d1871654SHans de Goede static const struct edt_i2c_chip_data edt_ft6236_data = { 1483d1871654SHans de Goede .max_support_points = 2, 1484d1871654SHans de Goede }; 1485d1871654SHans de Goede 148643c4d13eSSimon Budig static const struct i2c_device_id edt_ft5x06_ts_id[] = { 1487b1d2a3ecSFranklin S Cooper Jr { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, 1488af33e0adSFranklin S Cooper Jr { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, 1489a2f39dacSMarco Felsch { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data }, 1490d1871654SHans de Goede /* Note no edt- prefix for compatibility with the ft6236.c driver */ 1491d1871654SHans de Goede { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, 14921730d814SLothar Waßmann { /* sentinel */ } 149343c4d13eSSimon Budig }; 149443c4d13eSSimon Budig MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); 149543c4d13eSSimon Budig 1496dac90dc2SLothar Waßmann static const struct of_device_id edt_ft5x06_of_match[] = { 1497b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data }, 1498b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, 1499b1d2a3ecSFranklin S Cooper Jr { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, 1500af33e0adSFranklin S Cooper Jr { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, 1501a2f39dacSMarco Felsch { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, 1502d1871654SHans de Goede /* Note focaltech vendor prefix for compatibility with ft6236.c */ 1503d1871654SHans de Goede { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, 1504dac90dc2SLothar Waßmann { /* sentinel */ } 1505dac90dc2SLothar Waßmann }; 1506dac90dc2SLothar Waßmann MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); 1507dac90dc2SLothar Waßmann 150843c4d13eSSimon Budig static struct i2c_driver edt_ft5x06_ts_driver = { 150943c4d13eSSimon Budig .driver = { 151043c4d13eSSimon Budig .name = "edt_ft5x06", 1511fc226eb2SAndy Shevchenko .of_match_table = edt_ft5x06_of_match, 15126e6ebfc5SJonathan Cameron .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops), 15130f58daaaSAhmad Fatoum .probe_type = PROBE_PREFER_ASYNCHRONOUS, 151443c4d13eSSimon Budig }, 151543c4d13eSSimon Budig .id_table = edt_ft5x06_ts_id, 1516e7c31218SUwe Kleine-König .probe_new = edt_ft5x06_ts_probe, 15171cb0aa88SBill Pemberton .remove = edt_ft5x06_ts_remove, 151843c4d13eSSimon Budig }; 151943c4d13eSSimon Budig 152043c4d13eSSimon Budig module_i2c_driver(edt_ft5x06_ts_driver); 152143c4d13eSSimon Budig 152243c4d13eSSimon Budig MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>"); 152343c4d13eSSimon Budig MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver"); 15246d3a41abSAndy Shevchenko MODULE_LICENSE("GPL v2"); 1525