diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-24 11:16:06 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-24 11:16:06 -0700 |
| commit | e1611017870fa1582b5ff9ec0edc09542318daa6 (patch) | |
| tree | faff3dcc5bd72395f407a01922ac5366f9a76cea /drivers/input/touchscreen | |
| parent | f0e6f20cb52b14c2c441f04e21cef0c95d498cac (diff) | |
| parent | 7a0e692a0381254b2f77c54dec100cd3325a6fdf (diff) | |
Merge tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov:
- A new driver for Wacom W9000-series penabled touchscreens
- Updates to STM FTS driver adding support for reset line and preparing
the driver for STMFTS5 support
- Updates to RMI4 and IMS PCU drivers hardening the code
- Support for half-duplex mode restored in ADS7846 driver
- Updates to driver's device_id tables to use named initializers
- Removal of no longer used PCAP keys and touchscreen drivers (support
for the ezx series of phones was removed in 2022)
- Removal of xilinx_ps2 driver which is no longer used either
- Updates to userio to allow setting up additional serio port
characteristics (such as id, extra and proto)
- Assorted hardening and cleanup fixes for other drivers
* tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (72 commits)
Input: mms114 - fix touch indexing for MMS134S and MMS136
Input: elan_i2c - prevent division by zero and arithmetic underflow
Input: stop force-feedback timer when unregistering input devices
Input: iforce - bound the device-reported force-feedback effect index
Input: goodix - clamp the device-reported contact count
Input: mms114 - reject an oversized device packet size
Input: touchwin - reset the packet index on every complete packet
Input: rmi4 - update formatting in F12
Input: rmi4 - propagate proper error code in F12 sensor tuning
Input: rmi4 - simplify size calculations in F12
Input: rmi4 - use sizeof(*ptr) and idiomatic checks in f12 allocators
Input: rmi4 - use devm_kmalloc for F12 data packet buffer
Input: rmi4 - use flexible array member for IRQ masks in F12
Input: rmi4 - use unaligned access helpers in F12
Input: rmi4 - change reg_size type to u32
Input: rmi4 - refactor F12 probe function
Input: rmi4 - use kzalloc_flex() for struct rmi_function
Input: rmi4 - refactor function allocation and registration
Input: rmi4 - use local presence map in rmi_read_register_desc()
Input: rmi4 - fix limit in rmi_register_desc_has_subpacket()
...
Diffstat (limited to 'drivers/input/touchscreen')
46 files changed, 833 insertions, 413 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aeaf9a9cbb41..9b9ae8ac3f7f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -610,6 +610,18 @@ config TOUCHSCREEN_WACOM_I2C To compile this driver as a module, choose M here: the module will be called wacom_i2c. +config TOUCHSCREEN_WACOM_W9000 + tristate "Wacom W9000-series penabled touchscreen (I2C)" + depends on I2C + help + Say Y here if you have a Wacom W9000-series penabled I2C touchscreen. + This driver supports models W9002 and W9007A. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module + will be called wacom_w9000. + config TOUCHSCREEN_LPC32XX tristate "LPC32XX touchscreen controller" depends on ARCH_LPC32XX @@ -1178,16 +1190,6 @@ config TOUCHSCREEN_TSC2007_IIO or ambient light monitoring), temperature and raw input values. -config TOUCHSCREEN_PCAP - tristate "Motorola PCAP touchscreen" - depends on EZX_PCAP - help - Say Y here if you have a Motorola EZX telephone and - want to enable support for the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called pcap_ts. - config TOUCHSCREEN_RM_TS tristate "Raydium I2C Touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f2b002abebe8..bfd9de83389d 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o -obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o @@ -101,6 +100,7 @@ tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o +obj-$(CONFIG_TOUCHSCREEN_WACOM_W9000) += wacom_w9000.o obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index e5b99312c3d9..c1ccdf86b74c 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ad7879_id[] = { - { "ad7879" }, - { "ad7889" }, + { .name = "ad7879" }, + { .name = "ad7889" }, { } }; MODULE_DEVICE_TABLE(i2c, ad7879_id); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 4b39f7212d35..8d6416ac283e 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -134,6 +134,9 @@ struct ads7846 { bool disabled; /* P: lock */ bool suspended; /* P: lock */ + int (*setup_spi_msg)(struct ads7846 *ts, + const struct ads7846_platform_data *pdata); + void (*read_state)(struct ads7846 *ts); int (*filter)(void *data, int data_idx, int *val); void *filter_data; int (*get_pendown_state)(void); @@ -325,7 +328,6 @@ struct ser_req { u8 ref_on; u8 command; u8 ref_off; - u16 scratch; struct spi_message msg; struct spi_transfer xfer[8]; /* @@ -333,6 +335,7 @@ struct ser_req { * transfer buffers to live in their own cache lines. */ __be16 sample ____cacheline_aligned; + u16 scratch; }; struct ads7845_ser_req { @@ -403,8 +406,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) spi_message_add_tail(&req->xfer[5], &req->msg); /* clear the command register */ - req->scratch = 0; - req->xfer[6].tx_buf = &req->scratch; + req->xfer[6].rx_buf = &req->scratch; req->xfer[6].len = 1; spi_message_add_tail(&req->xfer[6], &req->msg); @@ -789,6 +791,22 @@ static int ads7846_filter(struct ads7846 *ts) return 0; } +static int ads7846_filter_one(struct ads7846 *ts, unsigned int cmd_idx) +{ + struct ads7846_packet *packet = ts->packet; + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + int action, val; + + val = ads7846_get_value(&packet->rx[l->offset + l->count - 1]); + action = ts->filter(ts->filter_data, cmd_idx, &val); + if (action == ADS7846_FILTER_REPEAT) + return -EAGAIN; + else if (action != ADS7846_FILTER_OK) + return -EIO; + ads7846_set_cmd_val(ts, cmd_idx, val); + return 0; +} + static void ads7846_wait_for_hsync(struct ads7846 *ts) { if (ts->wait_for_sync) { @@ -811,6 +829,45 @@ static void ads7846_wait_for_hsync(struct ads7846 *ts) cpu_relax(); } +static void ads7846_halfd_read_state(struct ads7846 *ts) +{ + struct ads7846_packet *packet = ts->packet; + int msg_idx = 0; + + packet->ignore = false; + + while (msg_idx < ts->msg_count) { + int error; + + ads7846_wait_for_hsync(ts); + + error = spi_sync(ts->spi, &ts->msg[msg_idx]); + if (error) { + dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n", + error); + packet->ignore = true; + return; + } + + /* + * Last message is power down request, no need to convert + * or filter the value. + */ + if (msg_idx == ts->msg_count - 1) + break; + + error = ads7846_filter_one(ts, msg_idx); + if (error == -EAGAIN) { + continue; + } else if (error) { + packet->ignore = true; + msg_idx = ts->msg_count - 1; + } else { + msg_idx++; + } + } +} + static void ads7846_read_state(struct ads7846 *ts) { struct ads7846_packet *packet = ts->packet; @@ -939,7 +996,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) while (!ts->stopped && get_pendown_state(ts)) { /* pen is down, continue with the measurement */ - ads7846_read_state(ts); + ts->read_state(ts); if (!ts->stopped) ads7846_report_state(ts); @@ -1026,6 +1083,102 @@ static int ads7846_setup_pendown(struct spi_device *spi, * Set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ +static int ads7846_halfd_spi_msg(struct ads7846 *ts, + const struct ads7846_platform_data *pdata) +{ + struct spi_message *m = ts->msg; + struct spi_transfer *x = ts->xfer; + struct ads7846_packet *packet = ts->packet; + int vref = pdata->keep_vref_on; + unsigned int offset = 0; + unsigned int cmd_idx, b; + size_t size = 0; + + if (pdata->settle_delay_usecs) + packet->count = 2; + else + packet->count = 1; + + if (ts->model == 7846) + packet->cmds = 5; /* x, y, z1, z2, pwdown */ + else + packet->cmds = 3; /* x, y, pwdown */ + + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + unsigned int max_count; + + if (cmd_idx == packet->cmds - 1) { + cmd_idx = ADS7846_PWDOWN; + max_count = 1; + } else { + max_count = packet->count; + } + + l->offset = offset; + offset += max_count; + l->count = max_count; + l->skip = 0; + size += sizeof(*packet->rx) * max_count; + } + + /* We use two transfers per command. */ + if (ARRAY_SIZE(ts->xfer) < offset * 2) + return -ENOMEM; + + packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); + if (!packet->rx) + return -ENOMEM; + + if (ts->model == 7873) { + /* + * The AD7873 is almost identical to the ADS7846 + * keep VREF off during differential/ratiometric + * conversion modes. + */ + ts->model = 7846; + vref = 0; + } + + ts->msg_count = 0; + + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + u8 cmd; + + ts->msg_count++; + spi_message_init(m); + m->context = ts; + + if (cmd_idx == packet->cmds - 1) + cmd_idx = ADS7846_PWDOWN; + + cmd = ads7846_get_cmd(cmd_idx, vref); + + for (b = 0; b < l->count; b++) { + packet->rx[l->offset + b].cmd = cmd; + x->tx_buf = &packet->rx[l->offset + b].cmd; + x->len = 1; + spi_message_add_tail(x, m); + x++; + x->rx_buf = &packet->rx[l->offset + b].data; + x->len = 2; + if (b < l->count - 1 && l->count > 1) { + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; + } + spi_message_add_tail(x, m); + x++; + } + m++; + } + return 0; +} + +/* + * Set up the transfers to read touchscreen state; this assumes we + * use formula #2 for pressure, not #3. + */ static int ads7846_setup_spi_msg(struct ads7846 *ts, const struct ads7846_platform_data *pdata) { @@ -1236,6 +1389,14 @@ static int ads7846_probe(struct spi_device *spi) if (!ts) return -ENOMEM; + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { + ts->setup_spi_msg = ads7846_halfd_spi_msg; + ts->read_state = ads7846_halfd_read_state; + } else { + ts->setup_spi_msg = ads7846_setup_spi_msg; + ts->read_state = ads7846_read_state; + } + packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL); if (!packet) return -ENOMEM; @@ -1330,7 +1491,9 @@ static int ads7846_probe(struct spi_device *spi) ts->core_prop.swap_x_y = true; } - ads7846_setup_spi_msg(ts, pdata); + err = ts->setup_spi_msg(ts, pdata); + if (err) + return err; ts->reg = devm_regulator_get(dev, "vcc"); if (IS_ERR(ts->reg)) { diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 8a588202447d..aa43fc1549df 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -164,7 +164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "ar1021" }, + { .name = "ar1021" }, { } }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f21bf2844112..2c0e5a67135b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1397,7 +1397,8 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) { struct device *dev = &data->client->dev; struct mxt_object *object; - unsigned int type, instance, size, byte_offset; + unsigned int type, instance, size; + int byte_offset; int offset; int ret; int i; @@ -2840,14 +2841,12 @@ static ssize_t mxt_object_show(struct device *dev, int count = 0; int i, j; int error; - u8 *obuf; /* Pre-allocate buffer large enough to hold max sized object. */ - obuf = kmalloc(256, GFP_KERNEL); + u8 *obuf __free(kfree) = kmalloc(256, GFP_KERNEL); if (!obuf) return -ENOMEM; - error = 0; for (i = 0; i < data->info->object_num; i++) { object = data->object_table + i; @@ -2862,15 +2861,13 @@ static ssize_t mxt_object_show(struct device *dev, error = __mxt_read_reg(data->client, addr, size, obuf); if (error) - goto done; + return error; count = mxt_show_instance(buf, count, object, j, obuf); } } -done: - kfree(obuf); - return error ?: count; + return count; } static int mxt_check_firmware_format(struct device *dev, @@ -3420,11 +3417,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id); #endif static const struct i2c_device_id mxt_id[] = { - { "qt602240_ts" }, - { "atmel_mxt_ts" }, - { "atmel_mxt_tp" }, - { "maxtouch" }, - { "mXT224" }, + { .name = "qt602240_ts" }, + { .name = "atmel_mxt_ts" }, + { .name = "atmel_mxt_tp" }, + { .name = "maxtouch" }, + { .name = "mXT224" }, { } }; MODULE_DEVICE_TABLE(i2c, mxt_id); diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 401b2264f585..6c6ebebacba9 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -618,7 +618,7 @@ static int auo_pixcir_probe(struct i2c_client *client) } static const struct i2c_device_id auo_pixcir_idtable[] = { - { "auo_pixcir_ts" }, + { .name = "auo_pixcir_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 6baebb7ec089..d1bdccc56fc8 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -597,7 +597,7 @@ static int bu21013_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume); static const struct i2c_device_id bu21013_id[] = { - { DRIVER_TP }, + { .name = DRIVER_TP }, { } }; MODULE_DEVICE_TABLE(i2c, bu21013_id); diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 68d9cd55ceeb..339fee1622fb 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -442,7 +442,7 @@ static int bu21029_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume); static const struct i2c_device_id bu21029_ids[] = { - { DRIVER_NAME }, + { .name = DRIVER_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, bu21029_ids); diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c index 2d4b6e343203..0ac48eff3376 100644 --- a/drivers/input/touchscreen/cy8ctma140.c +++ b/drivers/input/touchscreen/cy8ctma140.c @@ -322,7 +322,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm, cy8ctma140_suspend, cy8ctma140_resume); static const struct i2c_device_id cy8ctma140_idtable[] = { - { CY8CTMA140_NAME }, + { .name = CY8CTMA140_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable); diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 54d6c4869eb0..33ad4f0512a0 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -267,7 +267,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); static const struct i2c_device_id cy8ctmg110_idtable[] = { - { CY8CTMG110_DRIVER_NAME, 1 }, + { .name = CY8CTMG110_DRIVER_NAME, .driver_data = 1 }, { } }; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 47f4271395a6..73c397e44da4 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -938,7 +938,7 @@ static const struct of_device_id cyttsp5_of_match[] = { MODULE_DEVICE_TABLE(of, cyttsp5_of_match); static const struct i2c_device_id cyttsp5_i2c_id[] = { - { CYTTSP5_NAME }, + { .name = CYTTSP5_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index cb15600549cd..17524f7e944d 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -103,7 +103,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id cyttsp_i2c_id[] = { - { CY_I2C_NAME }, + { .name = CY_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 492e19a28a74..b12602bc368e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -266,7 +266,7 @@ static int eeti_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); static const struct i2c_device_id eeti_ts_id[] = { - { "eeti_ts" }, + { .name = "eeti_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, eeti_ts_id); diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index eb3cc2befcdf..76cf8085553f 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -219,7 +219,7 @@ static int egalax_ts_probe(struct i2c_client *client) } static const struct i2c_device_id egalax_ts_id[] = { - { "egalax_ts" }, + { .name = "egalax_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, egalax_ts_id); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 835d91dff0a4..17175adcaebb 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1615,9 +1615,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, elants_i2c_suspend, elants_i2c_resume); static const struct i2c_device_id elants_i2c_id[] = { - { DEVICE_NAME, EKTH3500 }, - { "ekth3500", EKTH3500 }, - { "ektf3624", EKTF3624 }, + { .name = DEVICE_NAME, .driver_data = EKTH3500 }, + { .name = "ekth3500", .driver_data = EKTH3500 }, + { .name = "ektf3624", .driver_data = EKTF3624 }, { } }; MODULE_DEVICE_TABLE(i2c, elants_i2c_id); diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 78c0911ba6e2..037bb35238a3 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -432,10 +432,10 @@ static int exc3000_probe(struct i2c_client *client) } static const struct i2c_device_id exc3000_id[] = { - { "exc3000", EETI_EXC3000 }, - { "exc80h60", EETI_EXC80H60 }, - { "exc80h84", EETI_EXC80H84 }, - { "exc81w32", EETI_EXC81W32 }, + { .name = "exc3000", .driver_data = EETI_EXC3000 }, + { .name = "exc80h60", .driver_data = EETI_EXC80H60 }, + { .name = "exc80h84", .driver_data = EETI_EXC80H84 }, + { .name = "exc81w32", .driver_data = EETI_EXC81W32 }, { } }; MODULE_DEVICE_TABLE(i2c, exc3000_id); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f8798d11ec03..03efc0c792c2 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1057,7 +1057,8 @@ static void goodix_read_config(struct goodix_ts_data *ts) } ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; - ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f; + ts->max_touch_num = min(ts->config[MAX_CONTACTS_LOC] & 0x0f, + GOODIX_MAX_CONTACTS); x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]); y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]); @@ -1523,7 +1524,7 @@ static int goodix_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume); static const struct i2c_device_id goodix_ts_id[] = { - { "GDIX1001:00" }, + { .name = "GDIX1001:00" }, { } }; MODULE_DEVICE_TABLE(i2c, goodix_ts_id); diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 62041bcca83d..58e00c314ace 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -1081,7 +1081,7 @@ static int hideep_probe(struct i2c_client *client) } static const struct i2c_device_id hideep_i2c_id[] = { - { HIDEEP_I2C_NAME }, + { .name = HIDEEP_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, hideep_i2c_id); diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c index 896a145ddb2b..0aa67dfacbad 100644 --- a/drivers/input/touchscreen/himax_hx83112b.c +++ b/drivers/input/touchscreen/himax_hx83112b.c @@ -406,8 +406,8 @@ static const struct himax_chip hx83112b_chip = { }; static const struct i2c_device_id himax_ts_id[] = { - { "hx83100a", (kernel_ulong_t)&hx83100a_chip }, - { "hx83112b", (kernel_ulong_t)&hx83112b_chip }, + { .name = "hx83100a", .driver_data = (kernel_ulong_t)&hx83100a_chip }, + { .name = "hx83112b", .driver_data = (kernel_ulong_t)&hx83112b_chip }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, himax_ts_id); diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c index b64d7928e18f..47d9cd7412d1 100644 --- a/drivers/input/touchscreen/hynitron-cst816x.c +++ b/drivers/input/touchscreen/hynitron-cst816x.c @@ -226,7 +226,7 @@ static int cst816x_probe(struct i2c_client *client) } static const struct i2c_device_id cst816x_id[] = { - { .name = "cst816s", 0 }, + { .name = "cst816s" }, { } }; MODULE_DEVICE_TABLE(i2c, cst816x_id); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 3bf524a6ee20..66ada7ffbc80 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -1049,10 +1049,10 @@ static int ili210x_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ili210x_i2c_id[] = { - { "ili210x", (long)&ili210x_chip }, - { "ili2117", (long)&ili211x_chip }, - { "ili2120", (long)&ili212x_chip }, - { "ili251x", (long)&ili251x_chip }, + { .name = "ili210x", .driver_data = (long)&ili210x_chip }, + { .name = "ili2117", .driver_data = (long)&ili211x_chip }, + { .name = "ili2120", .driver_data = (long)&ili212x_chip }, + { .name = "ili251x", .driver_data = (long)&ili251x_chip }, { } }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index 0706443792ba..3de0fbf8da38 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -639,7 +639,7 @@ static int ilitek_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume); static const struct i2c_device_id ilitek_ts_i2c_id[] = { - { ILITEK_TS_NAME }, + { .name = ILITEK_TS_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 587665e4e6fd..b9bbe8b3eab8 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1049,9 +1049,9 @@ static int iqs5xx_probe(struct i2c_client *client) } static const struct i2c_device_id iqs5xx_id[] = { - { "iqs550", 0 }, - { "iqs572", 1 }, - { "iqs525", 2 }, + { .name = "iqs550" }, + { .name = "iqs572" }, + { .name = "iqs525" }, { } }; MODULE_DEVICE_TABLE(i2c, iqs5xx_id); diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index f39633fc8dc2..3996e4a61ff7 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -213,7 +213,7 @@ static int max11801_ts_probe(struct i2c_client *client) } static const struct i2c_device_id max11801_ts_id[] = { - { "max11801" }, + { .name = "max11801" }, { } }; MODULE_DEVICE_TABLE(i2c, max11801_ts_id); diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 10fccf4e5bb1..fd6c0ac301a2 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1536,7 +1536,7 @@ MODULE_DEVICE_TABLE(acpi, mip4_acpi_match); #endif static const struct i2c_device_id mip4_i2c_ids[] = { - { MIP4_DEVICE_NAME }, + { .name = MIP4_DEVICE_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids); diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 993d945dcd23..9d221e340404 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -211,7 +211,7 @@ static int migor_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume); static const struct i2c_device_id migor_ts_id[] = { - { "migor_ts" }, + { .name = "migor_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, migor_ts_id); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index af462086a65c..53ad35d61d47 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -217,7 +217,9 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) struct mms114_data *data = dev_id; struct i2c_client *client = data->client; struct mms114_touch touch[MMS114_MAX_TOUCH]; + struct mms114_touch *t; int packet_size; + int event_size; int touch_size; int index; int error; @@ -226,11 +228,19 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) if (packet_size <= 0) goto out; + if (packet_size > sizeof(touch)) { + dev_err(&client->dev, "Invalid packet size %d (max %zu)\n", + packet_size, sizeof(touch)); + goto out; + } + /* MMS136 has slightly different event size */ if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136) - touch_size = packet_size / MMS136_EVENT_SIZE; + event_size = MMS136_EVENT_SIZE; else - touch_size = packet_size / MMS114_EVENT_SIZE; + event_size = MMS114_EVENT_SIZE; + + touch_size = packet_size / event_size; error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, (u8 *)touch); @@ -238,18 +248,20 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) goto out; for (index = 0; index < touch_size; index++) { - switch (touch[index].type) { + t = (struct mms114_touch *)((u8 *)touch + index * event_size); + + switch (t->type) { case MMS114_TYPE_TOUCHSCREEN: - mms114_process_mt(data, touch + index); + mms114_process_mt(data, t); break; case MMS114_TYPE_TOUCHKEY: - mms114_process_touchkey(data, touch + index); + mms114_process_touchkey(data, t); break; default: dev_err(&client->dev, "Wrong touch type (%d)\n", - touch[index].type); + t->type); break; } } @@ -667,7 +679,7 @@ static int mms114_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); static const struct i2c_device_id mms114_id[] = { - { "mms114" }, + { .name = "mms114" }, { } }; MODULE_DEVICE_TABLE(i2c, mms114_id); diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 708bfb933ddd..0f771f681952 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -326,8 +326,8 @@ static const struct of_device_id nvt_ts_of_match[] = { MODULE_DEVICE_TABLE(of, nvt_ts_of_match); static const struct i2c_device_id nvt_ts_i2c_id[] = { - { "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data }, - { "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data }, + { .name = "nt11205-ts", .driver_data = (unsigned long)&nvt_nt11205_ts_data }, + { .name = "nt36672a-ts", .driver_data = (unsigned long)&nvt_nt36672a_ts_data }, { } }; MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c deleted file mode 100644 index 7b89eb74b9de..000000000000 --- a/drivers/input/touchscreen/pcap_ts.c +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform. - * - * Copyright (C) 2006 Harald Welte <laforge@openezx.org> - * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/pm.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/input.h> -#include <linux/mfd/ezx-pcap.h> - -struct pcap_ts { - struct pcap_chip *pcap; - struct input_dev *input; - struct delayed_work work; - u16 x, y; - u16 pressure; - u8 read_state; -}; - -#define SAMPLE_DELAY 20 /* msecs */ - -#define X_AXIS_MIN 0 -#define X_AXIS_MAX 1023 -#define Y_AXIS_MAX X_AXIS_MAX -#define Y_AXIS_MIN X_AXIS_MIN -#define PRESSURE_MAX X_AXIS_MAX -#define PRESSURE_MIN X_AXIS_MIN - -static void pcap_ts_read_xy(void *data, u16 res[2]) -{ - struct pcap_ts *pcap_ts = data; - - switch (pcap_ts->read_state) { - case PCAP_ADC_TS_M_PRESSURE: - /* pressure reading is unreliable */ - if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX) - pcap_ts->pressure = res[0]; - pcap_ts->read_state = PCAP_ADC_TS_M_XY; - schedule_delayed_work(&pcap_ts->work, 0); - break; - case PCAP_ADC_TS_M_XY: - pcap_ts->y = res[0]; - pcap_ts->x = res[1]; - if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || - pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { - /* pen has been released */ - input_report_abs(pcap_ts->input, ABS_PRESSURE, 0); - input_report_key(pcap_ts->input, BTN_TOUCH, 0); - - pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; - schedule_delayed_work(&pcap_ts->work, 0); - } else { - /* pen is touching the screen */ - input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); - input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); - input_report_key(pcap_ts->input, BTN_TOUCH, 1); - input_report_abs(pcap_ts->input, ABS_PRESSURE, - pcap_ts->pressure); - - /* switch back to pressure read mode */ - pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; - schedule_delayed_work(&pcap_ts->work, - msecs_to_jiffies(SAMPLE_DELAY)); - } - input_sync(pcap_ts->input); - break; - default: - dev_warn(&pcap_ts->input->dev, - "pcap_ts: Warning, unhandled read_state %d\n", - pcap_ts->read_state); - break; - } -} - -static void pcap_ts_work(struct work_struct *work) -{ - struct delayed_work *dw = to_delayed_work(work); - struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); - u8 ch[2]; - - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - - if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) - return; - - /* start adc conversion */ - ch[0] = PCAP_ADC_CH_TS_X1; - ch[1] = PCAP_ADC_CH_TS_Y1; - pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch, - pcap_ts_read_xy, pcap_ts); -} - -static irqreturn_t pcap_ts_event_touch(int pirq, void *data) -{ - struct pcap_ts *pcap_ts = data; - - if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) { - pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; - schedule_delayed_work(&pcap_ts->work, 0); - } - return IRQ_HANDLED; -} - -static int pcap_ts_open(struct input_dev *dev) -{ - struct pcap_ts *pcap_ts = input_get_drvdata(dev); - - pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; - schedule_delayed_work(&pcap_ts->work, 0); - - return 0; -} - -static void pcap_ts_close(struct input_dev *dev) -{ - struct pcap_ts *pcap_ts = input_get_drvdata(dev); - - cancel_delayed_work_sync(&pcap_ts->work); - - pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); -} - -static int pcap_ts_probe(struct platform_device *pdev) -{ - struct input_dev *input_dev; - struct pcap_ts *pcap_ts; - int err = -ENOMEM; - - pcap_ts = kzalloc_obj(*pcap_ts); - if (!pcap_ts) - return err; - - pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent); - platform_set_drvdata(pdev, pcap_ts); - - input_dev = input_allocate_device(); - if (!input_dev) - goto fail; - - INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work); - - pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - - pcap_ts->input = input_dev; - input_set_drvdata(input_dev, pcap_ts); - - input_dev->name = "pcap-touchscreen"; - input_dev->phys = "pcap_ts/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0001; - input_dev->id.product = 0x0002; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - input_dev->open = pcap_ts_open; - input_dev->close = pcap_ts_close; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, - PRESSURE_MAX, 0, 0); - - err = input_register_device(pcap_ts->input); - if (err) - goto fail_allocate; - - err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), - pcap_ts_event_touch, 0, "Touch Screen", pcap_ts); - if (err) - goto fail_register; - - return 0; - -fail_register: - input_unregister_device(input_dev); - goto fail; -fail_allocate: - input_free_device(input_dev); -fail: - kfree(pcap_ts); - - return err; -} - -static void pcap_ts_remove(struct platform_device *pdev) -{ - struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); - - free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts); - cancel_delayed_work_sync(&pcap_ts->work); - - input_unregister_device(pcap_ts->input); - - kfree(pcap_ts); -} - -#ifdef CONFIG_PM -static int pcap_ts_suspend(struct device *dev) -{ - struct pcap_ts *pcap_ts = dev_get_drvdata(dev); - - pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR); - return 0; -} - -static int pcap_ts_resume(struct device *dev) -{ - struct pcap_ts *pcap_ts = dev_get_drvdata(dev); - - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - return 0; -} - -static const struct dev_pm_ops pcap_ts_pm_ops = { - .suspend = pcap_ts_suspend, - .resume = pcap_ts_resume, -}; -#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops) -#else -#define PCAP_TS_PM_OPS NULL -#endif - -static struct platform_driver pcap_ts_driver = { - .probe = pcap_ts_probe, - .remove = pcap_ts_remove, - .driver = { - .name = "pcap-ts", - .pm = PCAP_TS_PM_OPS, - }, -}; -module_platform_driver(pcap_ts_driver); - -MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); -MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcap_ts"); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index c6b3615c8775..1ca5920846df 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -580,8 +580,8 @@ static const struct pixcir_i2c_chip_data pixcir_tangoc_data = { }; static const struct i2c_device_id pixcir_i2c_ts_id[] = { - { "pixcir_ts", (unsigned long) &pixcir_ts_data }, - { "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data }, + { .name = "pixcir_ts", .driver_data = (unsigned long)&pixcir_ts_data }, + { .name = "pixcir_tangoc", .driver_data = (unsigned long)&pixcir_tangoc_data }, { } }; MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index f2d33ad86fd2..0256055abcef 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1219,8 +1219,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, raydium_i2c_suspend, raydium_i2c_resume); static const struct i2c_device_id raydium_i2c_id[] = { - { "raydium_i2c" }, - { "rm32380" }, + { .name = "raydium_i2c" }, + { .name = "rm32380" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, raydium_i2c_id); diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 295d8d75ba32..a5c06b7423c0 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -1144,7 +1144,7 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id rohm_bu21023_i2c_id[] = { - { BU21023_NAME }, + { .name = BU21023_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id); diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index e1518a75a51b..0f24a9b73063 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, s6sy761_of_match); #endif static const struct i2c_device_id s6sy761_id[] = { - { "s6sy761" }, + { .name = "s6sy761" }, { } }; MODULE_DEVICE_TABLE(i2c, s6sy761_id); diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 5ccc96764742..44d7141103f4 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -776,12 +776,12 @@ static int silead_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume); static const struct i2c_device_id silead_ts_id[] = { - { "gsl1680" }, - { "gsl1688" }, - { "gsl3670" }, - { "gsl3675" }, - { "gsl3692" }, - { "mssl1680" }, + { .name = "gsl1680" }, + { .name = "gsl1688" }, + { .name = "gsl3670" }, + { .name = "gsl3675" }, + { .name = "gsl3692" }, + { .name = "mssl1680" }, { } }; MODULE_DEVICE_TABLE(i2c, silead_ts_id); diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c index a625f2ad809d..4fa93cd31ee4 100644 --- a/drivers/input/touchscreen/sis_i2c.c +++ b/drivers/input/touchscreen/sis_i2c.c @@ -374,8 +374,8 @@ MODULE_DEVICE_TABLE(of, sis_ts_dt_ids); #endif static const struct i2c_device_id sis_ts_id[] = { - { SIS_I2C_NAME }, - { "9200-ts" }, + { .name = SIS_I2C_NAME }, + { .name = "9200-ts" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, sis_ts_id); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 9b266927b7fe..c2dcfce5003d 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -453,8 +453,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, st1232_ts_suspend, st1232_ts_resume); static const struct i2c_device_id st1232_ts_id[] = { - { ST1232_TS_NAME, (unsigned long)&st1232_chip_info }, - { ST1633_TS_NAME, (unsigned long)&st1633_chip_info }, + { .name = ST1232_TS_NAME, .driver_data = (unsigned long)&st1232_chip_info }, + { .name = ST1633_TS_NAME, .driver_data = (unsigned long)&st1633_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, st1232_ts_id); diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 8af87d0b6eb6..972687797f82 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -5,6 +5,7 @@ // Copyright (c) 2017 Andi Shyti <andi@etezian.org> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> @@ -69,20 +70,21 @@ #define STMFTS_MAX_FINGERS 10 #define STMFTS_DEV_NAME "stmfts" -enum stmfts_regulators { - STMFTS_REGULATOR_VDD, - STMFTS_REGULATOR_AVDD, +static const struct regulator_bulk_data stmfts_supplies[] = { + { .supply = "vdd" }, + { .supply = "avdd" }, }; struct stmfts_data { struct i2c_client *client; struct input_dev *input; + struct gpio_desc *reset_gpio; struct led_classdev led_cdev; struct mutex mutex; struct touchscreen_properties prop; - struct regulator_bulk_data regulators[2]; + struct regulator_bulk_data *supplies; /* * Presence of ledvdd will be used also to check @@ -107,7 +109,7 @@ struct stmfts_data { }; static int stmfts_brightness_set(struct led_classdev *led_cdev, - enum led_brightness value) + enum led_brightness value) { struct stmfts_data *sdata = container_of(led_cdev, struct stmfts_data, led_cdev); @@ -250,7 +252,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata) u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE]; switch (event[0]) { - case STMFTS_EV_CONTROLLER_READY: case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY: case STMFTS_EV_STATUS: @@ -263,7 +264,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata) } switch (event[0] & STMFTS_MASK_EVENT_ID) { - case STMFTS_EV_MULTI_TOUCH_ENTER: case STMFTS_EV_MULTI_TOUCH_MOTION: stmfts_report_contact_event(sdata, event); @@ -285,9 +285,9 @@ static void stmfts_parse_events(struct stmfts_data *sdata) case STMFTS_EV_ERROR: dev_warn(&sdata->client->dev, - "error code: 0x%x%x%x%x%x%x", - event[6], event[5], event[4], - event[3], event[2], event[1]); + "error code: 0x%x%x%x%x%x%x", + event[6], event[5], event[4], + event[3], event[2], event[1]); break; default: @@ -404,7 +404,7 @@ static void stmfts_input_close(struct input_dev *dev) } static ssize_t stmfts_sysfs_chip_id(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -412,7 +412,8 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev, } static ssize_t stmfts_sysfs_chip_version(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -420,7 +421,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev, } static ssize_t stmfts_sysfs_fw_ver(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -428,7 +429,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev, } static ssize_t stmfts_sysfs_config_id(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -436,7 +437,8 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev, } static ssize_t stmfts_sysfs_config_version(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -444,7 +446,8 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev, } static ssize_t stmfts_sysfs_read_status(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); u8 status[4]; @@ -459,7 +462,8 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev, } static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -467,8 +471,8 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, } static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct stmfts_data *sdata = dev_get_drvdata(dev); unsigned long value; @@ -485,8 +489,8 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, if (hover != sdata->hover_enabled) { if (sdata->running) { err = i2c_smbus_write_byte(sdata->client, - value ? STMFTS_SS_HOVER_SENSE_ON : - STMFTS_SS_HOVER_SENSE_OFF); + value ? STMFTS_SS_HOVER_SENSE_ON : + STMFTS_SS_HOVER_SENSE_OFF); if (err) return err; } @@ -518,22 +522,11 @@ static struct attribute *stmfts_sysfs_attrs[] = { }; ATTRIBUTE_GROUPS(stmfts_sysfs); -static int stmfts_power_on(struct stmfts_data *sdata) +static int stmfts_read_system_info(struct stmfts_data *sdata) { int err; u8 reg[8]; - err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators), - sdata->regulators); - if (err) - return err; - - /* - * The datasheet does not specify the power on time, but considering - * that the reset time is < 10ms, I sleep 20ms to be sure - */ - msleep(20); - err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO, sizeof(reg), reg); if (err < 0) @@ -547,9 +540,21 @@ static int stmfts_power_on(struct stmfts_data *sdata) sdata->config_id = reg[4]; sdata->config_ver = reg[5]; - enable_irq(sdata->client->irq); + return 0; +} +static void stmfts_reset(struct stmfts_data *sdata) +{ + gpiod_set_value_cansleep(sdata->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(sdata->reset_gpio, 0); msleep(50); +} + +static int stmfts_configure(struct stmfts_data *sdata) +{ + int err; err = stmfts_command(sdata, STMFTS_SYSTEM_RESET); if (err) @@ -575,13 +580,52 @@ static int stmfts_power_on(struct stmfts_data *sdata) if (err) return err; + return 0; +} + +static int stmfts_power_on(struct stmfts_data *sdata) +{ + int err; + + err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies), + sdata->supplies); + if (err) + return err; + + /* + * The datasheet does not specify the power on time, but considering + * that the reset time is < 10ms, I sleep 20ms to be sure + */ + msleep(20); + + if (sdata->reset_gpio) + stmfts_reset(sdata); + + err = stmfts_read_system_info(sdata); + if (err) + goto err_disable_regulators; + + enable_irq(sdata->client->irq); + + msleep(50); + + err = stmfts_configure(sdata); + if (err) + goto err_disable_irq; + /* * At this point no one is using the touchscreen * and I don't really care about the return value */ - (void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); + (void)i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); return 0; + +err_disable_irq: + disable_irq(sdata->client->irq); +err_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies); + return err; } static void stmfts_power_off(void *data) @@ -589,8 +633,11 @@ static void stmfts_power_off(void *data) struct stmfts_data *sdata = data; disable_irq(sdata->client->irq); - regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), - sdata->regulators); + + if (sdata->reset_gpio) + gpiod_set_value_cansleep(sdata->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies); } static int stmfts_enable_led(struct stmfts_data *sdata) @@ -619,6 +666,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata) static int stmfts_probe(struct i2c_client *client) { + struct device *dev = &client->dev; int err; struct stmfts_data *sdata; @@ -627,7 +675,7 @@ static int stmfts_probe(struct i2c_client *client) I2C_FUNC_SMBUS_I2C_BLOCK)) return -ENODEV; - sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL); + sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); if (!sdata) return -ENOMEM; @@ -637,15 +685,19 @@ static int stmfts_probe(struct i2c_client *client) mutex_init(&sdata->mutex); init_completion(&sdata->cmd_done); - sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd"; - sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd"; - err = devm_regulator_bulk_get(&client->dev, - ARRAY_SIZE(sdata->regulators), - sdata->regulators); + err = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(stmfts_supplies), + stmfts_supplies, + &sdata->supplies); if (err) return err; - sdata->input = devm_input_allocate_device(&client->dev); + sdata->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sdata->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio), + "Failed to get GPIO 'reset'\n"); + + sdata->input = devm_input_allocate_device(dev); if (!sdata->input) return -ENOMEM; @@ -664,8 +716,7 @@ static int stmfts_probe(struct i2c_client *client) input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0); - sdata->use_key = device_property_read_bool(&client->dev, - "touch-key-connected"); + sdata->use_key = device_property_read_bool(dev, "touch-key-connected"); if (sdata->use_key) { input_set_capability(sdata->input, EV_KEY, KEY_MENU); input_set_capability(sdata->input, EV_KEY, KEY_BACK); @@ -685,20 +736,20 @@ static int stmfts_probe(struct i2c_client *client) * interrupts. To be on the safe side it's better to not enable * the interrupts during their request. */ - err = devm_request_threaded_irq(&client->dev, client->irq, + err = devm_request_threaded_irq(dev, client->irq, NULL, stmfts_irq_handler, IRQF_ONESHOT | IRQF_NO_AUTOEN, "stmfts_irq", sdata); if (err) return err; - dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n"); + dev_dbg(dev, "initializing ST-Microelectronics FTS...\n"); err = stmfts_power_on(sdata); if (err) return err; - err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata); + err = devm_add_action_or_reset(dev, stmfts_power_off, sdata); if (err) return err; @@ -715,13 +766,13 @@ static int stmfts_probe(struct i2c_client *client) * without LEDs. The ledvdd regulator pointer will be * used as a flag. */ - dev_warn(&client->dev, "unable to use touchkey leds\n"); + dev_warn(dev, "unable to use touchkey leds\n"); sdata->ledvdd = NULL; } } - pm_runtime_enable(&client->dev); - device_enable_async_suspend(&client->dev); + pm_runtime_enable(dev); + device_enable_async_suspend(dev); return 0; } @@ -746,9 +797,10 @@ static int stmfts_runtime_suspend(struct device *dev) static int stmfts_runtime_resume(struct device *dev) { struct stmfts_data *sdata = dev_get_drvdata(dev); + struct i2c_client *client = sdata->client; int ret; - ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT); + ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT); if (ret) dev_err(dev, "failed to resume device: %d\n", ret); @@ -785,7 +837,7 @@ MODULE_DEVICE_TABLE(of, stmfts_of_match); #endif static const struct i2c_device_id stmfts_id[] = { - { "stmfts" }, + { .name = "stmfts" }, { } }; MODULE_DEVICE_TABLE(i2c, stmfts_id); @@ -807,4 +859,4 @@ module_i2c_driver(stmfts_driver); MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 099fd88e65d8..3ed33378dfcd 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -63,12 +63,15 @@ static irqreturn_t tw_interrupt(struct serio *serio, if (data) { /* touch */ tw->touched = 1; tw->data[tw->idx++] = data; - /* verify length and that the two Y's are the same */ - if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { - input_report_abs(dev, ABS_X, tw->data[0]); - input_report_abs(dev, ABS_Y, tw->data[1]); - input_report_key(dev, BTN_TOUCH, 1); - input_sync(dev); + /* a full packet ends the accumulation, valid or not */ + if (tw->idx == TW_LENGTH) { + /* report only if the two Y's are the same */ + if (tw->data[1] == tw->data[2]) { + input_report_abs(dev, ABS_X, tw->data[0]); + input_report_abs(dev, ABS_Y, tw->data[1]); + input_report_key(dev, BTN_TOUCH, 1); + input_sync(dev); + } tw->idx = 0; } } else if (tw->touched) { /* untouch */ diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index 787f2caf4f73..130aeb735b65 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -43,7 +43,7 @@ static int tsc2004_probe(struct i2c_client *i2c) } static const struct i2c_device_id tsc2004_idtable[] = { - { "tsc2004" }, + { .name = "tsc2004" }, { } }; MODULE_DEVICE_TABLE(i2c, tsc2004_idtable); diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 524f14eb3da2..4a775c5df0ea 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -61,10 +61,8 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) /* turn y+ off, x- on; we'll use formula #1 */ tc->z1 = tsc2007_xfer(tsc, READ_Z1); - tc->z2 = tsc2007_xfer(tsc, READ_Z2); - - /* Prepare for next touch reading - power down ADC, enable PENIRQ */ - tsc2007_xfer(tsc, PWRDOWN); + /* Read Z2 and power down ADC after A/D conversion, enable PENIRQ */ + tc->z2 = tsc2007_xfer(tsc, (TSC2007_POWER_OFF_IRQ_EN | TSC2007_MEASURE_Z2)); } u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) @@ -407,7 +405,7 @@ static int tsc2007_probe(struct i2c_client *client) } static const struct i2c_device_id tsc2007_idtable[] = { - { "tsc2007" }, + { .name = "tsc2007" }, { } }; diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index fd97a83f5664..dd7c2a8a831b 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -253,7 +253,7 @@ static int wacom_i2c_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume); static const struct i2c_device_id wacom_i2c_id[] = { - { "WAC_I2C_EMR" }, + { .name = "WAC_I2C_EMR" }, { } }; MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); diff --git a/drivers/input/touchscreen/wacom_w9000.c b/drivers/input/touchscreen/wacom_w9000.c new file mode 100644 index 000000000000..4a2629a54167 --- /dev/null +++ b/drivers/input/touchscreen/wacom_w9000.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Wacom W9000-series penabled I2C touchscreen driver + * + * Copyright (c) 2026 Hendrik Noack <hendrik-noack@gmx.de> + * + * Partially based on vendor driver: + * Copyright (C) 2012, Samsung Electronics Co. Ltd. + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/lockdep.h> +#include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + +/* Some chips have flaky firmware that requires many retries before responding. */ +#define CMD_QUERY_RETRIES 8 + +/* Message length */ +#define CMD_QUERY_NUM_MAX 9 +#define MSG_COORD_NUM_MAX 12 + +/* Commands */ +#define CMD_QUERY 0x2a + +struct wacom_w9000_variant { + const u8 cmd_query_num; + const u8 msg_coord_num; + const char *name; +}; + +struct wacom_w9000_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct wacom_w9000_variant *variant; + u16 fw_version; + + struct touchscreen_properties prop; + u16 max_pressure; + + struct regulator *regulator; + + struct gpio_desc *flash_mode_gpio; + struct gpio_desc *reset_gpio; + + unsigned int irq; + + bool pen_proximity; +}; + +static int wacom_w9000_read(struct i2c_client *client, u8 command, u8 len, u8 *data) +{ + int error, res; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = &command, + .len = sizeof(command), + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = data, + .len = len, + } + }; + + res = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (res != ARRAY_SIZE(msg)) { + error = res < 0 ? res : -EIO; + dev_err(&client->dev, "%s: i2c transfer failed: %d (%d)\n", + __func__, error, res); + return error; + } + + return 0; +} + +static int wacom_w9000_query(struct wacom_w9000_data *wacom_data) +{ + struct i2c_client *client = wacom_data->client; + struct device *dev = &wacom_data->client->dev; + u8 data[CMD_QUERY_NUM_MAX]; + int retry; + int error; + + for (retry = 0; retry < CMD_QUERY_RETRIES; retry++) { + error = wacom_w9000_read(client, CMD_QUERY, + wacom_data->variant->cmd_query_num, + data); + if (!error && data[0] == 0x0f) + break; + } + + if (error) + return error; + + if (data[0] != 0x0f) + return -EIO; + + dev_dbg(dev, "query: %*ph, %d\n", + wacom_data->variant->cmd_query_num, data, retry); + + wacom_data->prop.max_x = get_unaligned_be16(&data[1]); + wacom_data->prop.max_y = get_unaligned_be16(&data[3]); + wacom_data->max_pressure = get_unaligned_be16(&data[5]); + wacom_data->fw_version = get_unaligned_be16(&data[7]); + + dev_dbg(dev, "max_x:%d, max_y:%d, max_pressure:%d, fw:%#x\n", + wacom_data->prop.max_x, wacom_data->prop.max_y, + wacom_data->max_pressure, wacom_data->fw_version); + + return 0; +} + +static int wacom_w9000_power_on(struct wacom_w9000_data *wacom_data) +{ + int error; + + lockdep_assert_held(&wacom_data->input_dev->mutex); + + error = regulator_enable(wacom_data->regulator); + if (error) { + dev_err(&wacom_data->client->dev, "Failed to enable regulators: %d\n", error); + return error; + } + + msleep(200); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); + enable_irq(wacom_data->irq); + + return 0; +} + +static int wacom_w9000_power_off(struct wacom_w9000_data *wacom_data) +{ + lockdep_assert_held(&wacom_data->input_dev->mutex); + + disable_irq(wacom_data->irq); + gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); + regulator_disable(wacom_data->regulator); + + return 0; +} + +static void wacom_w9000_coord(struct wacom_w9000_data *wacom_data) +{ + struct i2c_client *client = wacom_data->client; + struct device *dev = &wacom_data->client->dev; + u8 data[MSG_COORD_NUM_MAX]; + bool touch, rubber, side_button; + u16 x, y, pressure; + u8 distance = 0; + int error; + + error = i2c_master_recv(client, data, wacom_data->variant->msg_coord_num); + if (error != wacom_data->variant->msg_coord_num) { + if (error >= 0) + error = -EIO; + dev_err_ratelimited(dev, "%s: i2c receive failed (%d)\n", __func__, error); + return; + } + + dev_dbg(dev, "data: %*ph\n", wacom_data->variant->msg_coord_num, data); + + if (data[0] & BIT(7)) { + wacom_data->pen_proximity = true; + + touch = !!(data[0] & BIT(4)); + side_button = !!(data[0] & BIT(5)); + rubber = !!(data[0] & BIT(6)); + + x = get_unaligned_be16(&data[1]); + y = get_unaligned_be16(&data[3]); + pressure = get_unaligned_be16(&data[5]); + + if (wacom_data->variant->msg_coord_num > 7) + distance = data[7]; + + if (x > wacom_data->prop.max_x || y > wacom_data->prop.max_y) { + dev_warn_ratelimited(dev, "Coordinates out of range x=%d, y=%d\n", x, y); + return; + } + + if (pressure > wacom_data->max_pressure) { + dev_warn_ratelimited(dev, "Pressure out of range %d\n", pressure); + return; + } + + touchscreen_report_pos(wacom_data->input_dev, &wacom_data->prop, x, y, false); + input_report_abs(wacom_data->input_dev, ABS_PRESSURE, pressure); + + if (wacom_data->variant->msg_coord_num > 7) + input_report_abs(wacom_data->input_dev, ABS_DISTANCE, distance); + + input_report_key(wacom_data->input_dev, BTN_STYLUS, side_button); + input_report_key(wacom_data->input_dev, BTN_TOUCH, touch); + input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, !rubber); + input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, rubber); + input_sync(wacom_data->input_dev); + } else if (wacom_data->pen_proximity) { + input_report_abs(wacom_data->input_dev, ABS_PRESSURE, 0); + + if (wacom_data->variant->msg_coord_num > 7) + input_report_abs(wacom_data->input_dev, ABS_DISTANCE, 255); + + input_report_key(wacom_data->input_dev, BTN_STYLUS, 0); + input_report_key(wacom_data->input_dev, BTN_TOUCH, 0); + input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, 0); + input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, 0); + input_sync(wacom_data->input_dev); + + wacom_data->pen_proximity = false; + } +} + +static irqreturn_t wacom_w9000_interrupt(int irq, void *dev_id) +{ + struct wacom_w9000_data *wacom_data = dev_id; + + wacom_w9000_coord(wacom_data); + + return IRQ_HANDLED; +} + +static int wacom_w9000_open(struct input_dev *dev) +{ + struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); + + return wacom_w9000_power_on(wacom_data); +} + +static void wacom_w9000_close(struct input_dev *dev) +{ + struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); + + wacom_w9000_power_off(wacom_data); +} + +static int wacom_w9000_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct wacom_w9000_data *wacom_data; + struct input_dev *input_dev; + int error; + u32 val; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "i2c_check_functionality error\n"); + return -EIO; + } + + wacom_data = devm_kzalloc(dev, sizeof(*wacom_data), GFP_KERNEL); + if (!wacom_data) + return -ENOMEM; + + wacom_data->variant = i2c_get_match_data(client); + if (!wacom_data->variant) { + dev_err(dev, "No i2c match_data available\n"); + return -EINVAL; + } + + if (wacom_data->variant->cmd_query_num > CMD_QUERY_NUM_MAX || + wacom_data->variant->msg_coord_num > MSG_COORD_NUM_MAX) { + dev_err(dev, "Length of message for %s exceeds the maximum\n", + wacom_data->variant->name); + return -EINVAL; + } + + if (wacom_data->variant->msg_coord_num < 7) { + dev_err(dev, "Length of coordinates message for %s too short\n", + wacom_data->variant->name); + return -EINVAL; + } + + wacom_data->client = client; + wacom_data->irq = client->irq; + i2c_set_clientdata(client, wacom_data); + + wacom_data->regulator = devm_regulator_get(dev, "vdd"); + if (IS_ERR(wacom_data->regulator)) + return dev_err_probe(dev, PTR_ERR(wacom_data->regulator), + "Failed to get regulators\n"); + + wacom_data->flash_mode_gpio = devm_gpiod_get_optional(dev, "flash-mode", GPIOD_OUT_LOW); + if (IS_ERR(wacom_data->flash_mode_gpio)) + return dev_err_probe(dev, PTR_ERR(wacom_data->flash_mode_gpio), + "Failed to get flash-mode gpio\n"); + + wacom_data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(wacom_data->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wacom_data->reset_gpio), + "Failed to get reset gpio\n"); + + error = regulator_enable(wacom_data->regulator); + if (error) + return dev_err_probe(dev, error, "Failed to enable regulators\n"); + + msleep(200); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); + + error = wacom_w9000_query(wacom_data); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); + regulator_disable(wacom_data->regulator); + + if (error) + return dev_err_probe(dev, error, "Failed to query\n"); + + error = devm_request_threaded_irq(dev, wacom_data->irq, NULL, wacom_w9000_interrupt, + IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, wacom_data); + if (error) + return dev_err_probe(dev, error, "Failed to register interrupt\n"); + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) + return -ENOMEM; + + wacom_data->input_dev = input_dev; + input_set_drvdata(input_dev, wacom_data); + + input_dev->name = wacom_data->variant->name; + input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0x56a; + input_dev->id.version = wacom_data->fw_version; + input_dev->open = wacom_w9000_open; + input_dev->close = wacom_w9000_close; + + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + input_set_capability(input_dev, EV_KEY, BTN_TOOL_PEN); + input_set_capability(input_dev, EV_KEY, BTN_TOOL_RUBBER); + input_set_capability(input_dev, EV_KEY, BTN_STYLUS); + + input_set_abs_params(input_dev, ABS_X, 0, wacom_data->prop.max_x, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, wacom_data->prop.max_y, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_data->max_pressure, 0, 0); + + if (wacom_data->variant->msg_coord_num > 7) + input_set_abs_params(input_dev, ABS_DISTANCE, 0, 255, 0, 0); + + touchscreen_parse_properties(input_dev, false, &wacom_data->prop); + + dev_info(dev, "%s size X%uY%u\n", wacom_data->variant->name, + wacom_data->prop.max_x, wacom_data->prop.max_y); + + error = device_property_read_u32(dev, "touchscreen-x-mm", &val); + if (!error && val) + input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_Y : ABS_X, + wacom_data->prop.max_x / val); + error = device_property_read_u32(dev, "touchscreen-y-mm", &val); + if (!error && val) + input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_X : ABS_Y, + wacom_data->prop.max_y / val); + + error = input_register_device(wacom_data->input_dev); + if (error) + return dev_err_probe(dev, error, "Failed to register input device\n"); + + return 0; +} + +static int wacom_w9000_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); + + guard(mutex)(&wacom_data->input_dev->mutex); + + if (input_device_enabled(wacom_data->input_dev)) + return wacom_w9000_power_off(wacom_data); + + return 0; +} + +static int wacom_w9000_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); + + guard(mutex)(&wacom_data->input_dev->mutex); + + if (input_device_enabled(wacom_data->input_dev)) + return wacom_w9000_power_on(wacom_data); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(wacom_w9000_pm, wacom_w9000_suspend, wacom_w9000_resume); + +static const struct wacom_w9000_variant w9002 = { + .cmd_query_num = 9, + .msg_coord_num = 7, + .name = "Wacom W9002 Digitizer", +}; + +static const struct wacom_w9000_variant w9007a_lt03 = { + .cmd_query_num = 9, + .msg_coord_num = 8, + .name = "Wacom W9007A LT03 Digitizer", +}; + +static const struct wacom_w9000_variant w9007a_v1 = { + .cmd_query_num = 9, + .msg_coord_num = 12, + .name = "Wacom W9007A V1 Digitizer", +}; + +static const struct of_device_id wacom_w9000_of_match[] = { + { .compatible = "wacom,w9002", .data = &w9002 }, + { .compatible = "wacom,w9007a-lt03", .data = &w9007a_lt03, }, + { .compatible = "wacom,w9007a-v1", .data = &w9007a_v1, }, + { } +}; +MODULE_DEVICE_TABLE(of, wacom_w9000_of_match); + +static const struct i2c_device_id wacom_w9000_id[] = { + { .name = "w9002", .driver_data = (kernel_ulong_t)&w9002 }, + { .name = "w9007a-lt03", .driver_data = (kernel_ulong_t)&w9007a_lt03 }, + { .name = "w9007a-v1", .driver_data = (kernel_ulong_t)&w9007a_v1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wacom_w9000_id); + +static struct i2c_driver wacom_w9000_driver = { + .driver = { + .name = "wacom_w9000", + .of_match_table = wacom_w9000_of_match, + .pm = pm_sleep_ptr(&wacom_w9000_pm), + }, + .probe = wacom_w9000_probe, + .id_table = wacom_w9000_id, +}; +module_i2c_driver(wacom_w9000_driver); + +MODULE_AUTHOR("Hendrik Noack <hendrik-noack@gmx.de>"); +MODULE_DESCRIPTION("Wacom W9000-series penabled touchscreen driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index bdaabb14dc8c..1af309252092 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -1140,7 +1140,7 @@ static int wdt87xx_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume); static const struct i2c_device_id wdt87xx_dev_id[] = { - { WDT87XX_NAME }, + { .name = WDT87XX_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id); diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c index 943634ba9cd9..a341142f3708 100644 --- a/drivers/input/touchscreen/zet6223.c +++ b/drivers/input/touchscreen/zet6223.c @@ -236,7 +236,7 @@ static const struct of_device_id zet6223_of_match[] = { MODULE_DEVICE_TABLE(of, zet6223_of_match); static const struct i2c_device_id zet6223_id[] = { - { "zet6223" }, + { .name = "zet6223" }, { } }; MODULE_DEVICE_TABLE(i2c, zet6223_id); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index a360749fa076..4bfc9560bd6c 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -831,7 +831,7 @@ static int zforce_probe(struct i2c_client *client) } static const struct i2c_device_id zforce_idtable[] = { - { "zforce-ts" }, + { .name = "zforce-ts" }, { } }; MODULE_DEVICE_TABLE(i2c, zforce_idtable); |
