diff options
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/ad7877.c | 6 | ||||
-rw-r--r-- | drivers/input/touchscreen/ad7879.c | 19 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel-wm97xx.c | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp4_core.c | 59 | ||||
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 173 | ||||
-rw-r--r-- | drivers/input/touchscreen/elants_i2c.c | 19 | ||||
-rw-r--r-- | drivers/input/touchscreen/exc3000.c | 223 | ||||
-rw-r--r-- | drivers/input/touchscreen/goodix.c | 125 | ||||
-rw-r--r-- | drivers/input/touchscreen/melfas_mip4.c | 17 | ||||
-rw-r--r-- | drivers/input/touchscreen/mxs-lradc-ts.c | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/raydium_i2c_ts.c | 18 | ||||
-rw-r--r-- | drivers/input/touchscreen/rohm_bu21023.c | 17 | ||||
-rw-r--r-- | drivers/input/touchscreen/stmfts.c | 4 | ||||
-rw-r--r-- | drivers/input/touchscreen/tsc200x-core.c | 6 | ||||
-rw-r--r-- | drivers/input/touchscreen/w90p910_ts.c | 7 | ||||
-rw-r--r-- | drivers/input/touchscreen/wdt87xx_i2c.c | 10 |
18 files changed, 532 insertions, 196 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 64b30fe273fd..26a66bc7b2df 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL To compile this driver as a module, choose M here: the module will be called egalax_ts_serial. +config TOUCHSCREEN_EXC3000 + tristate "EETI EXC3000 multi-touch panel support" + depends on I2C + help + Say Y here to enable support for I2C connected EETI + EXC3000 multi-touch panels. + + To compile this driver as a module, choose M here: the + module will be called exc3000. + config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO @@ -949,7 +959,7 @@ config TOUCHSCREEN_USB_NEXIO config TOUCHSCREEN_USB_EASYTOUCH default y - bool "EasyTouch USB Touch controller device support" if EMBEDDED + bool "EasyTouch USB Touch controller device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE help Say Y here if you have an EasyTouch USB Touch controller. diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 850c1562555a..2fa458088e3b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o +obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 9c250ae780d9..0381c7809d1b 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) input_sync(input_dev); } -static void ad7877_timer(unsigned long handle) +static void ad7877_timer(struct timer_list *t) { - struct ad7877 *ts = (void *)handle; + struct ad7877 *ts = from_timer(ts, t, timer); unsigned long flags; spin_lock_irqsave(&ts->lock, flags); @@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi) ts->spi = spi; ts->input = input_dev; - setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts); + timer_setup(&ts->timer, ad7877_timer, 0); mutex_init(&ts->mutex); spin_lock_init(&ts->lock); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 196028c45210..6bad23ee47a1 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts) input_sync(input_dev); } -static void ad7879_timer(unsigned long handle) +static void ad7879_timer(struct timer_list *t) { - struct ad7879 *ts = (void *)handle; + struct ad7879 *ts = from_timer(ts, t, timer); ad7879_ts_event_release(ts); } @@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) return 0; } -static void ad7879_cleanup_sysfs(void *_ts) -{ - struct ad7879 *ts = _ts; - - sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); -} - int ad7879_probe(struct device *dev, struct regmap *regmap, int irq, u16 bustype, u8 devid) { @@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, ts->irq = irq; ts->regmap = regmap; - setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts); + timer_setup(&ts->timer, ad7879_timer, 0); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); input_dev->name = "AD7879 Touchscreen"; @@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, __ad7879_disable(ts); - err = sysfs_create_group(&dev->kobj, &ad7879_attr_group); - if (err) - return err; - - err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts); + err = devm_device_add_group(dev, &ad7879_attr_group); if (err) return err; diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 8cf0b2be2df4..9140a43cfe20 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -208,9 +208,12 @@ static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm) } } -static void atmel_wm97xx_pen_timer(unsigned long data) +static void atmel_wm97xx_pen_timer(struct timer_list *t) { - atmel_wm97xx_acc_pen_up((struct wm97xx *)data); + struct atmel_wm97xx *atmel_wm97xx = from_timer(atmel_wm97xx, t, + pen_timer); + + atmel_wm97xx_acc_pen_up(atmel_wm97xx->wm); } static int atmel_wm97xx_acc_startup(struct wm97xx *wm) @@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev) atmel_wm97xx->gpio_pen = atmel_gpio_line; atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen); - setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, - (unsigned long)wm); + timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0); ret = request_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx_channel_b_interrupt, diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index beaf61ce775b..727c3232517c 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd) void *p; int rc; + if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) { + dev_err(cd->dev, + "%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n", + __func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs); + return -EINVAL; + } + si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs; dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__, si->si_ofs.cydata_size); p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL); if (p == NULL) { - dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__); + dev_err(cd->dev, "%s: failed to allocate cydata memory\n", + __func__); return -ENOMEM; } si->si_ptrs.cydata = p; @@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd) void *p; int rc; + if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) { + dev_err(cd->dev, + "%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n", + __func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs); + return -EINVAL; + } + si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs; p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL); if (p == NULL) { - dev_err(cd->dev, "%s: fail alloc test memory\n", __func__); + dev_err(cd->dev, "%s: failed to allocate test memory\n", + __func__); return -ENOMEM; } si->si_ptrs.test = p; @@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd) void *p; int rc; + if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) { + dev_err(cd->dev, + "%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n", + __func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs); + return -EINVAL; + } + si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs; p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL); if (p == NULL) { - rc = -ENOMEM; - dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n", - __func__, rc); - return rc; + dev_err(cd->dev, "%s: failed to allocate pcfg memory\n", + __func__); + return -ENOMEM; } si->si_ptrs.pcfg = p; @@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) void *p; int rc; + if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) { + dev_err(cd->dev, + "%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n", + __func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs); + return -EINVAL; + } + si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs; p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL); if (p == NULL) { - dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__); - rc = -ENOMEM; - goto cyttsp4_si_get_opcfg_data_exit; + dev_err(cd->dev, "%s: failed to allocate opcfg memory\n", + __func__); + return -ENOMEM; } si->si_ptrs.opcfg = p; @@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) if (rc < 0) { dev_err(cd->dev, "%s: fail read opcfg data r=%d\n", __func__, rc); - goto cyttsp4_si_get_opcfg_data_exit; + return rc; } si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs; si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs; @@ -447,8 +476,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg, si->si_ofs.opcfg_size, "sysinfo_opcfg_data"); -cyttsp4_si_get_opcfg_data_exit: - return rc; + return 0; } static int cyttsp4_si_get_ddata(struct cyttsp4 *cd) @@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd) del_timer_sync(&cd->watchdog_timer); } -static void cyttsp4_watchdog_timer(unsigned long handle) +static void cyttsp4_watchdog_timer(struct timer_list *t) { - struct cyttsp4 *cd = (struct cyttsp4 *)handle; + struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer); dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); @@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, } /* Setup watchdog timer */ - setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer, - (unsigned long)cd); + timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0); /* * call startup directly to ensure that the device diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 5bf63f76ddda..c53a3d7239e7 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -70,8 +70,10 @@ #define EDT_RAW_DATA_DELAY 1000 /* usec */ enum edt_ver { - M06, - M09, + EDT_M06, + EDT_M09, + EDT_M12, + GENERIC_FT, }; struct edt_reg_addr { @@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) int error; switch (tsdata->version) { - case M06: + case EDT_M06: cmd = 0xf9; /* tell the controller to send touch data */ offset = 5; /* where the actual touch data starts */ tplen = 4; /* data comes in so called frames */ crclen = 1; /* length of the crc data */ break; - case M09: + case EDT_M09: + case EDT_M12: + case GENERIC_FT: cmd = 0x0; offset = 3; tplen = 6; @@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) goto out; } - /* M09 does not send header or CRC */ - if (tsdata->version == M06) { + /* M09/M12 does not send header or CRC */ + if (tsdata->version == EDT_M06) { if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != datalen) { dev_err_ratelimited(dev, @@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) continue; /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ - if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) + if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) continue; x = ((buf[0] << 8) | buf[1]) & 0x0fff; @@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, u8 wrbuf[4]; switch (tsdata->version) { - case M06: + case EDT_M06: wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; wrbuf[2] = value; wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); - case M09: + case EDT_M09: + case EDT_M12: + case GENERIC_FT: wrbuf[0] = addr; wrbuf[1] = value; @@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, int error; switch (tsdata->version) { - case M06: + case EDT_M06: wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; @@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, } break; - case M09: + case EDT_M09: + case EDT_M12: + case GENERIC_FT: wrbuf[0] = addr; error = edt_ft5x06_ts_readwrite(tsdata->client, 1, wrbuf, 1, rdbuf); @@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, } switch (tsdata->version) { - case M06: + case EDT_M06: addr = attr->addr_m06; break; - case M09: + case EDT_M09: + case EDT_M12: + case GENERIC_FT: addr = attr->addr_m09; break; @@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, } switch (tsdata->version) { - case M06: + case EDT_M06: addr = attr->addr_m06; break; - case M09: + case EDT_M09: + case EDT_M12: + case GENERIC_FT: addr = attr->addr_m09; break; @@ -466,14 +478,18 @@ out: return error ?: count; } +/* m06, m09: range 0-31, m12: range 0-5 */ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, M09_REGISTER_GAIN, 0, 31); +/* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, M09_REGISTER_OFFSET, 0, 31); +/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, - M09_REGISTER_THRESHOLD, 0, 80); + M09_REGISTER_THRESHOLD, 0, 255); +/* m06: range 3 to 14, m12: (0x64: 100Hz) */ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, - NO_REGISTER, 3, 14); + NO_REGISTER, 0, 255); static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, @@ -508,7 +524,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) } /* mode register is 0x3c when in the work mode */ - if (tsdata->version == M09) + if (tsdata->version != EDT_M06) goto m09_out; error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); @@ -545,7 +561,7 @@ err_out: return error; m09_out: - dev_err(&client->dev, "No factory mode support for M09\n"); + dev_err(&client->dev, "No factory mode support for M09/M12/GENERIC_FT\n"); return -EINVAL; } @@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, * to have garbage in there */ memset(rdbuf, 0, sizeof(rdbuf)); - error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", + error = edt_ft5x06_ts_readwrite(client, 1, "\xBB", EDT_NAME_LEN - 1, rdbuf); if (error) return error; - /* if we find something consistent, stay with that assumption - * at least M09 won't send 3 bytes here + /* Probe content for something consistent. + * M06 starts with a response byte, M12 gives the data directly. + * M09/Generic does not provide model number information. */ - if (!(strncasecmp(rdbuf + 1, "EP0", 3))) { - tsdata->version = M06; + if (!strncasecmp(rdbuf + 1, "EP0", 3)) { + tsdata->version = EDT_M06; /* remove last '$' end marker */ rdbuf[EDT_NAME_LEN - 1] = '\0'; @@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, *p++ = '\0'; strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); + } else if (!strncasecmp(rdbuf, "EP0", 3)) { + tsdata->version = EDT_M12; + + /* remove last '$' end marker */ + rdbuf[EDT_NAME_LEN - 2] = '\0'; + if (rdbuf[EDT_NAME_LEN - 3] == '$') + rdbuf[EDT_NAME_LEN - 3] = '\0'; + + /* look for Model/Version separator */ + p = strchr(rdbuf, '*'); + if (p) + *p++ = '\0'; + strlcpy(model_name, rdbuf, EDT_NAME_LEN); + strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); } else { - /* since there are only two versions around (M06, M09) */ - tsdata->version = M09; + /* If it is not an EDT M06/M12 touchscreen, then the model + * detection is a bit hairy. The different ft5x06 + * firmares around don't reliably implement the + * identification registers. Well, we'll take a shot. + * + * The main difference between generic focaltec based + * touches and EDT M09 is that we know how to retrieve + * the max coordinates for the latter. + */ + tsdata->version = GENERIC_FT; error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", 2, rdbuf); @@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, if (error) return error; - snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", - rdbuf[0] >> 4, rdbuf[0] & 0x0F); + /* This "model identification" is not exact. Unfortunately + * not all firmwares for the ft5x06 put useful values in + * the identification registers. + */ + switch (rdbuf[0]) { + case 0x35: /* EDT EP0350M09 */ + case 0x43: /* EDT EP0430M09 */ + case 0x50: /* EDT EP0500M09 */ + case 0x57: /* EDT EP0570M09 */ + case 0x70: /* EDT EP0700M09 */ + tsdata->version = EDT_M09; + snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", + rdbuf[0] >> 4, rdbuf[0] & 0x0F); + break; + case 0xa1: /* EDT EP1010ML00 */ + tsdata->version = EDT_M09; + snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", + rdbuf[0] >> 4, rdbuf[0] & 0x0F); + break; + case 0x5a: /* Solomon Goldentek Display */ + snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); + break; + default: + snprintf(model_name, EDT_NAME_LEN, + "generic ft5x06 (%02x)", + rdbuf[0]); + break; + } } return 0; @@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); - tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); - tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); + if (tsdata->version == EDT_M06 || + tsdata->version == EDT_M09 || + tsdata->version == EDT_M12) { + tsdata->num_x = edt_ft5x06_register_read(tsdata, + reg_addr->reg_num_x); + tsdata->num_y = edt_ft5x06_register_read(tsdata, + reg_addr->reg_num_y); + } else { + tsdata->num_x = -1; + tsdata->num_y = -1; + } } static void @@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) struct edt_reg_addr *reg_addr = &tsdata->reg_addr; switch (tsdata->version) { - case M06: + case EDT_M06: reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; reg_addr->reg_gain = WORK_REGISTER_GAIN; @@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; break; - case M09: + case EDT_M09: + case EDT_M12: reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_gain = M09_REGISTER_GAIN; @@ -880,6 +955,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_num_x = M09_REGISTER_NUM_X; reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; + + case GENERIC_FT: + /* this is a guesswork */ + reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; + reg_addr->reg_gain = M09_REGISTER_GAIN; + reg_addr->reg_offset = M09_REGISTER_OFFSET; + break; } } @@ -969,10 +1051,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; - input_set_abs_params(input, ABS_MT_POSITION_X, - 0, tsdata->num_x * 64 - 1, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, - 0, tsdata->num_y * 64 - 1, 0, 0); + if (tsdata->version == EDT_M06 || + tsdata->version == EDT_M09 || + tsdata->version == EDT_M12) { + input_set_abs_params(input, ABS_MT_POSITION_X, + 0, tsdata->num_x * 64 - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + 0, tsdata->num_y * 64 - 1, 0, 0); + } else { + /* Unknown maximum values. Specify via devicetree */ + input_set_abs_params(input, ABS_MT_POSITION_X, + 0, 65535, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + 0, 65535, 0, 0); + } touchscreen_parse_properties(input, true, &tsdata->prop); @@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } - error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group); + error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); if (error) return error; error = input_register_device(input); if (error) - goto err_remove_attrs; + return error; edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); device_init_wakeup(&client->dev, 1); @@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); return 0; - -err_remove_attrs: - sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); - return error; } static int edt_ft5x06_ts_remove(struct i2c_client *client) @@ -1027,7 +1115,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client) struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); edt_ft5x06_ts_teardown_debugfs(tsdata); - sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); return 0; } diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 0f4cda7282a2..e102d7764bc2 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = { .attrs = elants_attributes, }; -static void elants_i2c_remove_sysfs_group(void *_data) -{ - struct elants_data *ts = _data; - - sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); -} - static int elants_i2c_power_on(struct elants_data *ts) { int error; @@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client, if (!client->dev.of_node) device_init_wakeup(&client->dev, true); - error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group); + error = devm_device_add_group(&client->dev, &elants_attribute_group); if (error) { dev_err(&client->dev, "failed to create sysfs attributes: %d\n", error); return error; } - error = devm_add_action(&client->dev, - elants_i2c_remove_sysfs_group, ts); - if (error) { - elants_i2c_remove_sysfs_group(ts); - dev_err(&client->dev, - "Failed to add sysfs cleanup action: %d\n", - error); - return error; - } - return 0; } diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c new file mode 100644 index 000000000000..37437a53cd1a --- /dev/null +++ b/drivers/input/touchscreen/exc3000.c @@ -0,0 +1,223 @@ +/* + * Driver for I2C connected EETI EXC3000 multiple touch controller + * + * Copyright (C) 2017 Ahmet Inan <inan@distec.de> + * + * minimal implementation based on egalax_ts.c and egalax_i2c.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/timer.h> +#include <asm/unaligned.h> + +#define EXC3000_NUM_SLOTS 10 +#define EXC3000_SLOTS_PER_FRAME 5 +#define EXC3000_LEN_FRAME 66 +#define EXC3000_LEN_POINT 10 +#define EXC3000_MT_EVENT 6 +#define EXC3000_TIMEOUT_MS 100 + +struct exc3000_data { + struct i2c_client *client; + struct input_dev *input; + struct touchscreen_properties prop; + struct timer_list timer; + u8 buf[2 * EXC3000_LEN_FRAME]; +}; + +static void exc3000_report_slots(struct input_dev *input, + struct touchscreen_properties *prop, + const u8 *buf, int num) +{ + for (; num--; buf += EXC3000_LEN_POINT) { + if (buf[0] & BIT(0)) { + input_mt_slot(input, buf[1]); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + touchscreen_report_pos(input, prop, + get_unaligned_le16(buf + 2), + get_unaligned_le16(buf + 4), + true); + } + } +} + +static void exc3000_timer(struct timer_list *t) +{ + struct exc3000_data *data = from_timer(data, t, timer); + + input_mt_sync_frame(data->input); + input_sync(data->input); +} + +static int exc3000_read_frame(struct i2c_client *client, u8 *buf) +{ + int ret; + + ret = i2c_master_send(client, "'", 2); + if (ret < 0) + return ret; + + if (ret != 2) + return -EIO; + + ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME); + if (ret < 0) + return ret; + + if (ret != EXC3000_LEN_FRAME) + return -EIO; + + if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME || + buf[2] != EXC3000_MT_EVENT) + return -EINVAL; + + return 0; +} + +static int exc3000_read_data(struct i2c_client *client, + u8 *buf, int *n_slots) +{ + int error; + + error = exc3000_read_frame(client, buf); + if (error) + return error; + + *n_slots = buf[3]; + if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS) + return -EINVAL; + + if (*n_slots > EXC3000_SLOTS_PER_FRAME) { + /* Read 2nd frame to get the rest of the contacts. */ + error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME); + if (error) + return error; + + /* 2nd chunk must have number of contacts set to 0. */ + if (buf[EXC3000_LEN_FRAME + 3] != 0) + return -EINVAL; + } + + return 0; +} + +static irqreturn_t exc3000_interrupt(int irq, void *dev_id) +{ + struct exc3000_data *data = dev_id; + struct input_dev *input = data->input; + u8 *buf = data->buf; + int slots, total_slots; + int error; + + error = exc3000_read_data(data->client, buf, &total_slots); + if (error) { + /* Schedule a timer to release "stuck" contacts */ + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); + goto out; + } + + /* + * We read full state successfully, no contacts will be "stuck". + */ + del_timer_sync(&data->timer); + + while (total_slots > 0) { + slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); + exc3000_report_slots(input, &data->prop, buf + 4, slots); + total_slots -= slots; + buf += EXC3000_LEN_FRAME; + } + + input_mt_sync_frame(input); + input_sync(input); + +out: + return IRQ_HANDLED; +} + +static int exc3000_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct exc3000_data *data; + struct input_dev *input; + int error; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + timer_setup(&data->timer, exc3000_timer, 0); + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; + + data->input = input; + + input->name = "EETI EXC3000 Touch Screen"; + input->id.bustype = BUS_I2C; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0); + touchscreen_parse_properties(input, true, &data->prop); + + error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + error = input_register_device(input); + if (error) + return error; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, exc3000_interrupt, IRQF_ONESHOT, + client->name, data); + if (error) + return error; + + return 0; +} + +static const struct i2c_device_id exc3000_id[] = { + { "exc3000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, exc3000_id); + +#ifdef CONFIG_OF +static const struct of_device_id exc3000_of_match[] = { + { .compatible = "eeti,exc3000" }, + { } +}; +MODULE_DEVICE_TABLE(of, exc3000_of_match); +#endif + +static struct i2c_driver exc3000_driver = { + .driver = { + .name = "exc3000", + .of_match_table = of_match_ptr(exc3000_of_match), + }, + .id_table = exc3000_id, + .probe = exc3000_probe, +}; + +module_i2c_driver(exc3000_driver); + +MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); +MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b3bbad7d2282..69d0b8cbc71f 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -31,9 +31,18 @@ #include <linux/of.h> #include <asm/unaligned.h> +struct goodix_ts_data; + +struct goodix_chip_data { + u16 config_addr; + int config_len; + int (*check_config)(struct goodix_ts_data *, const struct firmware *); +}; + struct goodix_ts_data { struct i2c_client *client; struct input_dev *input_dev; + const struct goodix_chip_data *chip; int abs_x_max; int abs_y_max; bool swapped_x_y; @@ -41,7 +50,6 @@ struct goodix_ts_data { bool inverted_y; unsigned int max_touch_num; unsigned int int_trigger_type; - int cfg_len; struct gpio_desc *gpiod_int; struct gpio_desc *gpiod_rst; u16 id; @@ -69,7 +77,8 @@ struct goodix_ts_data { #define GOODIX_CMD_SCREEN_OFF 0x05 #define GOODIX_READ_COOR_ADDR 0x814E -#define GOODIX_REG_CONFIG_DATA 0x8047 +#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 +#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 #define GOODIX_REG_ID 0x8140 #define GOODIX_BUFFER_STATUS_READY BIT(7) @@ -79,6 +88,35 @@ struct goodix_ts_data { #define MAX_CONTACTS_LOC 5 #define TRIGGER_LOC 6 +static int goodix_check_cfg_8(struct goodix_ts_data *ts, + const struct firmware *cfg); +static int goodix_check_cfg_16(struct goodix_ts_data *ts, + const struct firmware *cfg); + +static const struct goodix_chip_data gt1x_chip_data = { + .config_addr = GOODIX_GT1X_REG_CONFIG_DATA, + .config_len = GOODIX_CONFIG_MAX_LENGTH, + .check_config = goodix_check_cfg_16, +}; + +static const struct goodix_chip_data gt911_chip_data = { + .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, + .config_len = GOODIX_CONFIG_911_LENGTH, + .check_config = goodix_check_cfg_8, +}; + +static const struct goodix_chip_data gt967_chip_data = { + .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, + .config_len = GOODIX_CONFIG_967_LENGTH, + .check_config = goodix_check_cfg_8, +}; + +static const struct goodix_chip_data gt9x_chip_data = { + .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, + .config_len = GOODIX_CONFIG_MAX_LENGTH, + .check_config = goodix_check_cfg_8, +}; + static const unsigned long goodix_irq_flags[] = { IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, @@ -177,22 +215,25 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) return goodix_i2c_write(client, reg, &value, sizeof(value)); } -static int goodix_get_cfg_len(u16 id) +static const struct goodix_chip_data *goodix_get_chip_data(u16 id) { switch (id) { + case 1151: + return >1x_chip_data; + case 911: case 9271: case 9110: case 927: case 928: - return GOODIX_CONFIG_911_LENGTH; + return >911_chip_data; case 912: case 967: - return GOODIX_CONFIG_967_LENGTH; + return >967_chip_data; default: - return GOODIX_CONFIG_MAX_LENGTH; + return >9x_chip_data; } } @@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts) ts->irq_flags, ts->client->name, ts); } -/** - * goodix_check_cfg - Checks if config fw is valid - * - * @ts: goodix_ts_data pointer - * @cfg: firmware config data - */ -static int goodix_check_cfg(struct goodix_ts_data *ts, - const struct firmware *cfg) +static int goodix_check_cfg_8(struct goodix_ts_data *ts, + const struct firmware *cfg) { - int i, raw_cfg_len; + int i, raw_cfg_len = cfg->size - 2; u8 check_sum = 0; - if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) { - dev_err(&ts->client->dev, - "The length of the config fw is not correct"); - return -EINVAL; - } - - raw_cfg_len = cfg->size - 2; for (i = 0; i < raw_cfg_len; i++) check_sum += cfg->data[i]; check_sum = (~check_sum) + 1; @@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, return 0; } +static int goodix_check_cfg_16(struct goodix_ts_data *ts, + const struct firmware *cfg) +{ + int i, raw_cfg_len = cfg->size - 3; + u16 check_sum = 0; + + for (i = 0; i < raw_cfg_len; i += 2) + check_sum += get_unaligned_be16(&cfg->data[i]); + check_sum = (~check_sum) + 1; + if (check_sum != get_unaligned_be16(&cfg->data[raw_cfg_len])) { + dev_err(&ts->client->dev, + "The checksum of the config fw is not correct"); + return -EINVAL; + } + + if (cfg->data[raw_cfg_len + 2] != 1) { + dev_err(&ts->client->dev, + "Config fw must have Config_Fresh register set"); + return -EINVAL; + } + + return 0; +} + +/** + * goodix_check_cfg - Checks if config fw is valid + * + * @ts: goodix_ts_data pointer + * @cfg: firmware config data + */ +static int goodix_check_cfg(struct goodix_ts_data *ts, + const struct firmware *cfg) +{ + if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) { + dev_err(&ts->client->dev, + "The length of the config fw is not correct"); + return -EINVAL; + } + + return ts->chip->check_config(ts, cfg); +} + /** * goodix_send_cfg - Write fw config to device * @@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts, if (error) return error; - error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data, + error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg->data, cfg->size); if (error) { dev_err(&ts->client->dev, "Failed to write config data: %d", @@ -511,8 +581,8 @@ static void goodix_read_config(struct goodix_ts_data *ts) u8 config[GOODIX_CONFIG_MAX_LENGTH]; int error; - error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, - config, ts->cfg_len); + error = goodix_i2c_read(ts->client, ts->chip->config_addr, + config, ts->chip->config_len); if (error) { dev_warn(&ts->client->dev, "Error reading config (%d), using defaults\n", @@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client) u8 test; while (retry++ < 2) { - error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA, + error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1); if (!error) return 0; @@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client, return error; } - ts->cfg_len = goodix_get_cfg_len(ts->id); + ts->chip = goodix_get_chip_data(ts->id); if (ts->gpiod_int && ts->gpiod_rst) { /* update device config */ @@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); #ifdef CONFIG_OF static const struct of_device_id goodix_of_match[] = { + { .compatible = "goodix,gt1151" }, { .compatible = "goodix,gt911" }, { .compatible = "goodix,gt9110" }, { .compatible = "goodix,gt912" }, diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 05108c2fea93..6892f0e28918 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = { .attrs = mip4_attrs, }; -static void mip4_sysfs_remove(void *_data) -{ - struct mip4_ts *ts = _data; - - sysfs_remove_group(&ts->client->dev.kobj, &mip4_attr_group); -} - static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mip4_ts *ts; @@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) return error; } - error = sysfs_create_group(&client->dev.kobj, &mip4_attr_group); + error = devm_device_add_group(&client->dev, &mip4_attr_group); if (error) { dev_err(&client->dev, "Failed to create sysfs attribute group: %d\n", error); return error; } - error = devm_add_action(&client->dev, mip4_sysfs_remove, ts); - if (error) { - mip4_sysfs_remove(ts); - dev_err(&client->dev, - "Failed to install sysfs remoce action: %d\n", error); - return error; - } - return 0; } diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c index 3707e927f770..c850b517854e 100644 --- a/drivers/input/touchscreen/mxs-lradc-ts.c +++ b/drivers/input/touchscreen/mxs-lradc-ts.c @@ -584,7 +584,7 @@ static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts) static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts) { - struct input_dev *input = ts->ts_input; + struct input_dev *input; struct device *dev = ts->dev; input = devm_input_allocate_device(dev); diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 4f1d3fd5d412..100538d64fff 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = { .attrs = raydium_i2c_attributes, }; -static void raydium_i2c_remove_sysfs_group(void *_data) -{ - struct raydium_data *ts = _data; - - sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group); -} - static int raydium_i2c_power_on(struct raydium_data *ts) { int error; @@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client, return error; } - error = sysfs_create_group(&client->dev.kobj, + error = devm_device_add_group(&client->dev, &raydium_i2c_attribute_group); if (error) { dev_err(&client->dev, "failed to create sysfs attributes: %d\n", @@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client, return error; } - error = devm_add_action(&client->dev, - raydium_i2c_remove_sysfs_group, ts); - if (error) { - raydium_i2c_remove_sysfs_group(ts); - dev_err(&client->dev, - "Failed to add sysfs cleanup action: %d\n", error); - return error; - } - return 0; } diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index eeaf6ff03597..bda0500c9b57 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev) ts->initialized = false; } -static void rohm_ts_remove_sysfs_group(void *_dev) -{ - struct device *dev = _dev; - - sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group); -} - static int rohm_bu21023_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client, return error; } - error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group); + error = devm_device_add_group(dev, &rohm_ts_attr_group); if (error) { dev_err(dev, "failed to create sysfs group: %d\n", error); return error; } - error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev); - if (error) { - rohm_ts_remove_sysfs_group(dev); - dev_err(dev, "Failed to add sysfs cleanup action: %d\n", - error); - return error; - } - return error; } diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 8c6c6178ec12..c12d01899939 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client, } } - err = sysfs_create_group(&sdata->client->dev.kobj, - &stmfts_attribute_group); + err = devm_device_add_group(&client->dev, &stmfts_attribute_group); if (err) return err; @@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client, static int stmfts_remove(struct i2c_client *client) { pm_runtime_disable(&client->dev); - sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group); return 0; } diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index 88ea5e1b72ae..542db26d7fd0 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -202,9 +202,9 @@ out: return IRQ_HANDLED; } -static void tsc200x_penup_timer(unsigned long data) +static void tsc200x_penup_timer(struct timer_list *t) { - struct tsc200x *ts = (struct tsc200x *)data; + struct tsc200x *ts = from_timer(ts, t, penup_timer); unsigned long flags; spin_lock_irqsave(&ts->lock, flags); @@ -506,7 +506,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, mutex_init(&ts->mutex); spin_lock_init(&ts->lock); - setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts); + timer_setup(&ts->penup_timer, tsc200x_penup_timer, 0); INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work); diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index da6004e97753..638c1d78ca3a 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void w90p910_check_pen_up(unsigned long data) +static void w90p910_check_pen_up(struct timer_list *t) { - struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data; + struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer); unsigned long flags; spin_lock_irqsave(&w90p910_ts->lock, flags); @@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev) w90p910_ts->input = input_dev; w90p910_ts->state = TS_IDLE; spin_lock_init(&w90p910_ts->lock); - setup_timer(&w90p910_ts->timer, w90p910_check_pen_up, - (unsigned long)w90p910_ts); + timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index a9132603ab34..d351efd18f89 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client, return error; } - error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group); + error = devm_device_add_group(&client->dev, &wdt87xx_attr_group); if (error) { dev_err(&client->dev, "create sysfs failed: %d\n", error); return error; @@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client, return 0; } -static int wdt87xx_ts_remove(struct i2c_client *client) -{ - sysfs_remove_group(&client->dev.kobj, &wdt87xx_attr_group); - - return 0; -} - static int __maybe_unused wdt87xx_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id); static struct i2c_driver wdt87xx_driver = { .probe = wdt87xx_ts_probe, - .remove = wdt87xx_ts_remove, .id_table = wdt87xx_dev_id, .driver = { .name = WDT87XX_NAME, |