* [PATCH 2/2] Input: Add support for Wacom W9000-series penabled touchscreens
From: Hendrik Noack @ 2025-12-05 16:49 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, linux-input, devicetree, linux-kernel
In-Reply-To: <20251205152858.14415-1-hendrik-noack@gmx.de>
Add driver for two Wacom W9007A variants. These are penabled touchscreens
supporting passive Wacom Pens and use I2C.
Signed-off-by: Hendrik Noack <hendrik-noack@gmx.de>
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/wacom_w9000.c | 480 ++++++++++++++++++++++++
3 files changed, 493 insertions(+)
create mode 100644 drivers/input/touchscreen/wacom_w9000.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 7d5b72ee07fa..40f7af0a681a 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 model 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
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index ab9abd151078..aa3915df83b2 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -102,6 +102,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/wacom_w9000.c b/drivers/input/touchscreen/wacom_w9000.c
new file mode 100644
index 000000000000..05c928646bc3
--- /dev/null
+++ b/drivers/input/touchscreen/wacom_w9000.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Wacom W9000-series penabled I2C touchscreen driver
+ *
+ * Copyright (c) 2025 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/unaligned.h>
+
+// Message length
+#define COM_COORD_NUM_MAX 12
+#define COM_QUERY_NUM_MAX 9
+
+// Commands
+#define COM_QUERY 0x2a
+
+struct wacom_w9000_variant {
+ int com_coord_num;
+ int com_query_num;
+ char *name;
+};
+
+struct wacom_w9000_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ const struct wacom_w9000_variant *variant;
+ unsigned int fw_version;
+
+ struct touchscreen_properties prop;
+ unsigned int max_pressure;
+
+ struct regulator *regulator;
+
+ struct gpio_desc *flash_mode_gpio;
+ struct gpio_desc *pen_inserted_gpio;
+
+ unsigned int irq;
+ unsigned int pen_insert_irq;
+
+ bool pen_inserted;
+ bool pen_proximity;
+};
+
+static int wacom_w9000_read(struct i2c_client *client, u8 command, int len, char *data)
+{
+ struct i2c_msg xfer[2];
+ bool retried = false;
+ int ret;
+
+ /* Write register */
+ xfer[0].addr = client->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &command;
+
+ /* Read data */
+ xfer[1].addr = client->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = len;
+ xfer[1].buf = data;
+
+retry:
+ ret = i2c_transfer(client->adapter, xfer, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else if (!retried) {
+ retried = true;
+ goto retry;
+ } else {
+ if (ret >= 0)
+ ret = -EIO;
+ dev_err(&client->dev, "%s: i2c transfer failed (%d)\n", __func__, ret);
+ }
+
+ return ret;
+}
+
+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;
+ bool retried = false;
+ int ret;
+ u8 data[COM_QUERY_NUM_MAX];
+
+retry:
+ ret = wacom_w9000_read(client, COM_QUERY, wacom_data->variant->com_query_num, data);
+ if (ret)
+ return ret;
+
+ if (data[0] == 0x0f) {
+ wacom_data->fw_version = get_unaligned_be16(&data[7]);
+ } else if (!retried) {
+ retried = true;
+ goto retry;
+ } else {
+ return -EIO;
+ }
+
+ dev_dbg(dev, "query: %X, %X, %X, %X, %X, %X, %X, %X, %X, %d\n", data[0], data[1], data[2],
+ data[3], data[4], data[5], data[6], data[7], data[8], retried);
+
+ 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]);
+
+ dev_dbg(dev, "max_x:%d, max_y:%d, max_pressure:%d, fw:0x%X", wacom_data->prop.max_x,
+ wacom_data->prop.max_y, wacom_data->max_pressure,
+ wacom_data->fw_version);
+
+ 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;
+ int ret;
+ u8 data[COM_COORD_NUM_MAX];
+ bool touch, rubber, side_button;
+ u16 x, y, pressure;
+ u8 distance;
+
+ ret = i2c_master_recv(client, data, wacom_data->variant->com_coord_num);
+ if (ret != wacom_data->variant->com_coord_num) {
+ if (ret >= 0)
+ ret = -EIO;
+ dev_err(dev, "%s: i2c receive failed (%d)\n", __func__, ret);
+ return;
+ }
+
+ dev_dbg(dev, "data: %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X", data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
+ data[11]);
+
+ if (data[0] & BIT(7)) {
+ wacom_data->pen_proximity = 1;
+
+ 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]);
+ distance = data[7];
+
+ if (!((x <= wacom_data->prop.max_x) && (y <= wacom_data->prop.max_y))) {
+ dev_warn(dev, "Coordinates out of range x=%d, y=%d", x, y);
+ return;
+ }
+
+ touchscreen_report_pos(wacom_data->input_dev, &wacom_data->prop, x, y, false);
+ input_report_abs(wacom_data->input_dev, ABS_PRESSURE, pressure);
+ 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);
+ input_report_abs(wacom_data->input_dev, ABS_DISTANCE, 0);
+ 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 = 0;
+ }
+ }
+}
+
+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 irqreturn_t wacom_w9000_interrupt_pen_insert(int irq, void *dev_id)
+{
+ struct wacom_w9000_data *wacom_data = dev_id;
+ struct device *dev = &wacom_data->client->dev;
+ int ret;
+
+ wacom_data->pen_inserted = gpiod_get_value(wacom_data->pen_inserted_gpio);
+
+ input_report_switch(wacom_data->input_dev, SW_PEN_INSERTED, wacom_data->pen_inserted);
+ input_sync(wacom_data->input_dev);
+
+ if (!wacom_data->pen_inserted && !regulator_is_enabled(wacom_data->regulator)) {
+ ret = regulator_enable(wacom_data->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return IRQ_HANDLED;
+ }
+ msleep(200);
+ enable_irq(wacom_data->irq);
+ } else if (wacom_data->pen_inserted && regulator_is_enabled(wacom_data->regulator)) {
+ disable_irq(wacom_data->irq);
+ regulator_disable(wacom_data->regulator);
+ }
+
+ dev_dbg(dev, "Pen inserted changed to %d", wacom_data->pen_inserted);
+
+ return IRQ_HANDLED;
+}
+
+static int wacom_w9000_open(struct input_dev *dev)
+{
+ struct wacom_w9000_data *wacom_data = input_get_drvdata(dev);
+ int ret;
+
+ if (!wacom_data->pen_inserted && !regulator_is_enabled(wacom_data->regulator)) {
+ ret = regulator_enable(wacom_data->regulator);
+ if (ret) {
+ dev_err(&wacom_data->client->dev, "Failed to enable regulators: %d\n",
+ ret);
+ return ret;
+ }
+ msleep(200);
+ enable_irq(wacom_data->irq);
+ }
+ return 0;
+}
+
+static void wacom_w9000_close(struct input_dev *dev)
+{
+ struct wacom_w9000_data *wacom_data = input_get_drvdata(dev);
+
+ if (regulator_is_enabled(wacom_data->regulator)) {
+ disable_irq(wacom_data->irq);
+ regulator_disable(wacom_data->regulator);
+ }
+}
+
+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 ret;
+ 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);
+
+ wacom_data->client = client;
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return -ENOMEM;
+ wacom_data->input_dev = input_dev;
+
+ 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->pen_inserted_gpio = devm_gpiod_get_optional(dev, "pen-inserted", GPIOD_IN);
+ if (IS_ERR(wacom_data->pen_inserted_gpio))
+ return dev_err_probe(dev, PTR_ERR(wacom_data->pen_inserted_gpio),
+ "Failed to get pen-insert gpio\n");
+
+ ret = regulator_enable(wacom_data->regulator);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ msleep(200);
+
+ ret = wacom_w9000_query(wacom_data);
+ if (ret)
+ goto err_disable_regulators;
+
+ input_dev->name = wacom_data->variant->name;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = dev;
+ 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);
+
+ // Calculate x and y resolution from size in devicetree
+ ret = device_property_read_u32(dev, "touchscreen-x-mm", &val);
+ if (ret)
+ input_abs_set_res(input_dev, ABS_X, 100);
+ else
+ input_abs_set_res(input_dev, ABS_X, wacom_data->prop.max_x / val);
+ ret = device_property_read_u32(dev, "touchscreen-y-mm", &val);
+ if (ret)
+ input_abs_set_res(input_dev, ABS_Y, 100);
+ else
+ input_abs_set_res(input_dev, ABS_Y, wacom_data->prop.max_y / val);
+
+ 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);
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0, 255, 0, 0);
+
+ touchscreen_parse_properties(input_dev, false, &wacom_data->prop);
+
+ ret = devm_request_threaded_irq(dev, wacom_data->irq, NULL, wacom_w9000_interrupt,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, wacom_data);
+ if (ret) {
+ dev_err(dev, "Failed to register interrupt\n");
+ goto err_disable_regulators;
+ }
+
+ if (wacom_data->pen_inserted_gpio) {
+ input_set_capability(input_dev, EV_SW, SW_PEN_INSERTED);
+ wacom_data->pen_insert_irq = gpiod_to_irq(wacom_data->pen_inserted_gpio);
+ ret = devm_request_threaded_irq(dev, wacom_data->pen_insert_irq, NULL,
+ wacom_w9000_interrupt_pen_insert, IRQF_ONESHOT |
+ IRQF_NO_AUTOEN | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING, "wacom_pen_insert",
+ wacom_data);
+ if (ret) {
+ dev_err(dev, "Failed to register pen-insert interrupt\n");
+ goto err_disable_regulators;
+ }
+
+ wacom_data->pen_inserted = gpiod_get_value(wacom_data->pen_inserted_gpio);
+ if (wacom_data->pen_inserted)
+ regulator_disable(wacom_data->regulator);
+ else
+ enable_irq(wacom_data->irq);
+ } else {
+ enable_irq(wacom_data->irq);
+ }
+
+ input_set_drvdata(input_dev, wacom_data);
+
+ input_report_switch(wacom_data->input_dev, SW_PEN_INSERTED, wacom_data->pen_inserted);
+ input_sync(wacom_data->input_dev);
+
+ if (wacom_data->pen_inserted_gpio)
+ enable_irq(wacom_data->pen_insert_irq);
+
+ ret = input_register_device(wacom_data->input_dev);
+ if (ret) {
+ dev_err(dev, "Failed to register input device: %d\n", ret);
+ goto err_disable_regulators;
+ }
+
+ return 0;
+
+err_disable_regulators:
+ regulator_disable(wacom_data->regulator);
+ return ret;
+}
+
+static void wacom_w9000_remove(struct i2c_client *client)
+{
+ struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client);
+
+ if (regulator_is_enabled(wacom_data->regulator))
+ regulator_disable(wacom_data->regulator);
+}
+
+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);
+ struct input_dev *input_dev = wacom_data->input_dev;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (regulator_is_enabled(wacom_data->regulator)) {
+ disable_irq(wacom_data->irq);
+ regulator_disable(wacom_data->regulator);
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ 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);
+ struct input_dev *input_dev = wacom_data->input_dev;
+ int ret = 0;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (!wacom_data->pen_inserted && !regulator_is_enabled(wacom_data->regulator)) {
+ ret = regulator_enable(wacom_data->regulator);
+ if (ret) {
+ dev_err(&wacom_data->client->dev, "Failed to enable regulators: %d\n",
+ ret);
+ } else {
+ msleep(200);
+ enable_irq(wacom_data->irq);
+ }
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(wacom_w9000_pm, wacom_w9000_suspend, wacom_w9000_resume);
+
+static const struct wacom_w9000_variant w9007a_lt03 = {
+ .com_coord_num = 8,
+ .com_query_num = 9,
+ .name = "Wacom W9007 LT03 Digitizer",
+};
+
+static const struct wacom_w9000_variant w9007a_v1 = {
+ .com_coord_num = 12,
+ .com_query_num = 9,
+ .name = "Wacom W9007 V1 Digitizer",
+};
+
+static const struct of_device_id wacom_w9000_of_match[] = {
+ { .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 = "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,
+ .remove = wacom_w9000_remove,
+ .id_table = wacom_w9000_id,
+};
+module_i2c_driver(wacom_w9000_driver);
+
+/* Module information */
+MODULE_AUTHOR("Hendrik Noack <hendrik-noack@gmx.de>");
+MODULE_DESCRIPTION("Wacom W9000-series penabled touchscreen driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: Input: Add Wacom W9000-series penabled touchscreens
From: Hendrik Noack @ 2025-12-05 15:26 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, linux-input, devicetree, linux-kernel,
Krzysztof Kozlowski
In-Reply-To: <20251205152858.14415-1-hendrik-noack@gmx.de>
Add bindings for two Wacom W9007 variants which can be found in tablets.
Signed-off-by: Hendrik Noack <hendrik-noack@gmx.de>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../input/touchscreen/wacom,w9007a-lt03.yaml | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
diff --git a/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
new file mode 100644
index 000000000000..80d12cb8392d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/wacom,w9007a-lt03.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wacom W9000-series penabled I2C touchscreen
+
+maintainers:
+ - Hendrik Noack <hendrik-noack@gmx.de>
+
+description: |
+ The W9000-series are penabled touchscreen controllers by Wacom.
+
+ The firmware of chips between devices can differ and with it also
+ how the chips behaves.
+
+allOf:
+ - $ref: touchscreen.yaml#
+
+properties:
+ compatible:
+ enum:
+ - wacom,w9007a-lt03
+ - wacom,w9007a-v1
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply:
+ description:
+ Optional regulator for the VDD digital voltage.
+
+ flash-mode-gpios:
+ maxItems: 1
+ description:
+ Optional GPIO specifier for the touchscreen's flash-mode pin.
+
+ pen-inserted-gpios:
+ maxItems: 1
+ description:
+ Optional GPIO specifier for the touchscreen's pen-insert pin.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ digitizer@56 {
+ compatible = "wacom,w9007a-lt03";
+ reg = <0x56>;
+ interrupt-parent = <&gpd1>;
+ interrupts = <1 IRQ_TYPE_EDGE_RISING>;
+
+ vdd-supply = <&stylus_reg>;
+
+ flash-mode-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>;
+ pen-inserted-gpios = <&gpx0 0 GPIO_ACTIVE_LOW>;
+
+ touchscreen-x-mm = <216>;
+ touchscreen-y-mm = <135>;
+ touchscreen-inverted-x;
+ };
+ };
--
2.43.0
^ permalink raw reply related
* [PATCH v3 0/2] Add support for Wacom W9000-series penabled touchscreens
From: Hendrik Noack @ 2025-12-05 15:26 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, linux-input, devicetree, linux-kernel
Add devicetree bindings and a driver for the Wacom W9000-series penabled
touchscreens.
The driver currently only contains the information for the W9007A, which I
tested on my devices. It should also work with other chips, such as W9001 or
W9010. However, I couldn't test it on these and the message length would
need to be added.
The pen-inserted-gpios is used to get if the pen is inserted in the device
or not. It's also used as an interrupt so that the power state of the chip
itself can be controlled depending on a change of the insertion state of
the pen.
Note: This is my first driver I have ever worked on so if there is
anything I can do to improve it please let me know!
Signed-off-by: Hendrik Noack <hendrik-noack@gmx.de>
---
Changes in v2:
- remove pdct-gpios, as it's unnecessary
- fix devicetree example
- adopt to kernel coding style
---
Changes in v3:
- fix missing include (thanks lkp@intel.com)
---
Hendrik Noack (2):
dt-bindings: Input: Add Wacom W9000-series penabled touchscreens
Input: Add support for Wacom W9000-series penabled touchscreens
.../input/touchscreen/wacom,w9007a-lt03.yaml | 79 +++
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/wacom_w9000.c | 480 ++++++++++++++++++
4 files changed, 572 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
create mode 100644 drivers/input/touchscreen/wacom_w9000.c
--
2.43.0
^ permalink raw reply
* [PATCH] HID: EVision: input mapping fix for K552 keyboard
From: PrakarshPanwar via B4 Relay @ 2025-12-05 13:57 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel, PrakarshPanwar
From: PrakarshPanwar <prakarshpanwar@gmail.com>
Added fix for Media Key in Redragon K552 keyboard
In Windows, this keyboard F1 Key opens Media Player,
but in Linux it opens System Settings.
This commit is a fix for that bug it remaps K552 F1 key
which outputs KEY_CONFIG(171) now outputs KEY_MEDIA(226)
It also restructures the input mapping code in hid-evision
Signed-off-by: PrakarshPanwar <prakarshpanwar@gmail.com>
---
drivers/hid/hid-evision.c | 39 ++++++++++++++++++++++++++++++++++++---
drivers/hid/hid-ids.h | 1 +
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-evision.c b/drivers/hid/hid-evision.c
index 3e7f43ab80bb63ba073bc71f72acdb5ffaed8202..f78861863d4fc8a1305948385aa561ab374ceb49 100644
--- a/drivers/hid/hid-evision.c
+++ b/drivers/hid/hid-evision.c
@@ -14,14 +14,29 @@
#include "hid-ids.h"
-static int evision_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+static int evision_k552_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- /* mapping only applies to USB_DEVICE_ID_EVISION_ICL01 */
- if (hdev->product != USB_DEVICE_ID_EVISION_ICL01)
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ /* report 3 */
+ case 0x183:
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_MEDIA);
+ break;
+ default:
return 0;
+ }
+
+ return 1;
+}
+static int evision_icl01_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
return 0;
@@ -41,6 +56,23 @@ static int evision_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
+static int evision_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ int ret = 0;
+
+ if (hdev->product == USB_DEVICE_ID_EVISION_ICL01) {
+ ret = evision_icl01_input_mapping(hdev, hi,
+ field, usage, bit, max);
+ } else if (hdev->product == USB_DEVICE_ID_EVISION_K552) {
+ ret = evision_k552_input_mapping(hdev, hi,
+ field, usage, bit, max);
+ }
+
+ return ret;
+}
+
#define REP_DSC_SIZE 236
#define USAGE_MAX_INDEX 59
@@ -59,6 +91,7 @@ static const __u8 *evision_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static const struct hid_device_id evision_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EVISION_ICL01) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EV_TELINK_RECEIVER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EVISION_K552) },
{ }
};
MODULE_DEVICE_TABLE(hid, evision_devices);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index d31711f1aaeccb4ec93c5a9056af605d1775e0c5..f30b383036c74ad48b2d6880a44b2f2ac5dab46e 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -478,6 +478,7 @@
#define USB_VENDOR_ID_EVISION 0x320f
#define USB_DEVICE_ID_EV_TELINK_RECEIVER 0x226f
+#define USB_DEVICE_ID_EVISION_K552 0X5000
#define USB_DEVICE_ID_EVISION_ICL01 0x5041
#define USB_VENDOR_ID_FFBEAST 0x045b
---
base-commit: 2061f18ad76ecaddf8ed17df81b8611ea88dbddd
change-id: 20251205-evision-k552-mapping-fix-3eb3cc692393
Best regards,
--
PrakarshPanwar <prakarshpanwar@gmail.com>
^ permalink raw reply related
* Re: [PATCH] HID: validate report length and constants
From: Davide Beatrici @ 2025-12-04 23:43 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Terry Junge, linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <b3131f6c322ac4c62c4b00142b55fde7@davidebeatrici.dev>
> report 8 has csize=16 rsize=16
> report 0 has csize=1 rsize=8
> report 0 is too short, (1 < 8)
>
> Which means we do enter the test and execute the memset()...
I added further debug prints to trace the flow after that:
hid-generic 0003:373B:1107.000F: report 8 has csize=16 rsize=16
hid-generic 0003:373B:1107.000F: Calling hiddev_report_event()
hid-generic 0003:373B:1107.000F: Calling hidraw_report_event()
hid-generic 0003:373B:1107.000F: Calling hid_process_report()
hid-generic 0003:373B:1107.000F: Calling hidinput_report_event()
hid-generic 0003:373B:1107.000E: report 0 has csize=1 rsize=8
hid-generic 0003:373B:1107.000E: report 0 is too short, (1 < 8)
hid-generic 0003:373B:1107.000E: Calling hidraw_report_event()
hid-generic 0003:373B:1107.000E: Calling hid_process_report()
hid-generic 0003:373B:1107.000E: Calling hidinput_report_event()
hid-generic 0003:373B:1107.0010: report 0 has csize=7 rsize=7
hid-generic 0003:373B:1107.0010: Calling hidraw_report_event()
hid-generic 0003:373B:1107.0010: Calling hid_process_report()
hid-generic 0003:373B:1107.0010: Calling hidinput_report_event()
The last report is a normal mouse movement.
^ permalink raw reply
* Re: [PATCH] HID: validate report length and constants
From: Davide Beatrici @ 2025-12-04 19:48 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Terry Junge, linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <dob7q77qxuv3rmr4kliqp5kic36updvh6qxj4ld2be353zi7ba@5qte5m5fsuwy>
> However, the device also shows an output report of size 1, but it is
> not
> supposed to send it as an input report. I wonder if the firmware bug is
> not that it tries to give the host the current state of its output
> report at plug (which is wrong but Windows must be papering over it).
On that note, I noticed the malformed packet is not sent upon
reconnecting the
device if it's been plugged in for some time.
When that happens I can reproduce the issue by enabling a wireless mode
through
the switch on the bottom and wait a bit before disabling it and
connecting the
device again.
I suspect the battery gets slightly discharged and the device sends a
"charging complete" signal or something.
> - the URB is of size 1, so the fact that the constant field is not 0
> means that we are just reading random memory at offset 1 in the
> provided data, so you might have a chance that it eventually becomes 0
Good point, if it's effectively random memory we cannot rely on that.
> - the fix should be focusing on the length of the provided report, not
> on the content. However, in hid_report_raw_event(), just before you
> inserted your call to your hid_validate_report(), there is already a
> check on the length of the report which memsets to 0 the rest of the
> buffer. This seems a little bit optimistic if the provided buffer from
> USB is exactly the size of the provided "size" argument.
> But then, why would you get random data in the const fields if there
> is a memset if the provided length is "1"?
>
> So, can you add a printk before your call to hid_validate_report() to
> show the provided "size" argument (csize), or just enable the hid_dbg()
> trace output which should tell us if we enter that test and do the
> memset (which I suppose we are not).
report 8 has csize=16 rsize=16
report 0 has csize=1 rsize=8
report 0 is too short, (1 < 8)
Which means we do enter the test and execute the memset()...
^ permalink raw reply
* Re: Regression: SYNA3602 I2C touchpad broken in Linux 6.17.7 (works in 6.17.6 and previous versions)
From: Thorsten Leemhuis @ 2025-12-04 15:10 UTC (permalink / raw)
To: Vijay
Cc: regressions, linux-kernel, linux-input, linux-pm, linux-acpi,
Benjamin Tissoires, jikos
In-Reply-To: <CAO-hwJJRisVpZWeSA+3_fLaa8_52f7ypUocDcD+PojuF3KjHYw@mail.gmail.com>
Lo!
@AM Vijay: 6.17.y will be EOL in about ten days, so this is unlikely to
get fixed there. The big question is:
Is 6.18 affected?
If it is, we need your help identifying want went wrong; if not, then
it's likely not worth looking closer into this
Ciao, Thorsten
On 11/28/25 09:05, Benjamin Tissoires wrote:
> Hi,
>
> On Fri, Nov 28, 2025 at 7:40 AM Vijay <vijayg0127@gmail.com> wrote:
>>
>> Hello,
>>
>> I would like to report a regression in the Linux kernel affecting I2C-HID
>> touchpads that run through the Intel ISH + DesignWare I2C controller.
>>
>> Hardware:
>> - Laptop: Infinix Y4 Max
>> - CPU: Intel (13th gen core i5)
>> - Touchpad: SYNA3602:00 093A:35ED (I2C HID)
>> - Bus path: SYNA3602 → i2c_designware → Intel ISH → HID
>> - OS: Linux (Arch/CachyOS)
>> - Kernel config: Default distro config
>>
>> Regression summary:
>> - Touchpad works perfectly in Linux 6.17.6 and below versions
>> - Touchpad stops working in Linux 6.17.7 and all newer versions (6.17.8, 6.17.9, etc.)
>> - Desktop environment does not matter (Hyprland/GNOME both fail)
>> - The failure happens before userspace loads
>> - Touchpad also works fine in Linux 6.12 LTS
>>
>> This is a kernel-level regression introduced between:
>> Good: Linux 6.17.6
>> Bad: Linux 6.17.7
>>
>> **Dmesg logs from broken kernel (6.17.7 and newer):**
>>
>> i2c-SYNA3602:00: can't add hid device: -110
>> hid_sensor_hub: reading report descriptor failed
>> intel-hid INTC1078:00: failed to enable HID power button
>
> Looks like i2c-hid can't even communicate with any I2C device, so this
> is slightly worrying.
>
>>
>> And the DesignWare I2C controller logs around the failure:
>> i2c_designware 0000:00:15.0: controller timed out
>> i2c_designware 0000:00:15.0: lost arbitration
>> i2c_designware 0000:00:15.0: transfer aborted (status = -110)
>>
>> These errors appear only on 6.17.7+ and not on 6.17.6.
>>
>> On working versions (6.17.6 and 6.12 LTS), the touchpad initializes normally:
>>
>> input: SYNA3602:00 093A:35ED Touchpad as /devices/.../input/inputX
>> hid-multitouch: I2C HID v1.00 device initialized
>> i2c_designware 0000:00:15.0: controller operating normally
>>
>> This narrow regression window should make it possible to identify the offending
>> change in either:
>> - HID core
>> - I2C-HID
>> - Intel ISH HID
>> - DesignWare I2C controller
>> - ACPI timing changes
>>
>> I can provide:
>> - Full dmesg (working and broken)
>> - acpidump
>
> Are you running on a full vanilla kernel?
>
> The changelog between 6.17.6 and 6.17.7 is rather small, so it should
> be easy enough to bisect and get the offending commit.
>
> I have my suspicions on:
> f1971d5ba2ef ("genirq/manage: Add buslock back in to enable_irq()")
> b990b4c6ea6b ("genirq/manage: Add buslock back in to __disable_irq_nosync()")
> 3c97437239df ("genirq/chip: Add buslock back in to irq_set_handler()")
>
> Because anything else is unrelated to any component involved in i2c-hid.
> (But that's also assuming you are running vanilla kernels without any
> extra patches.)
>
> OTOH, I've booted a 6.17.8 and 6.17.7 shipped by Fedora and I don't
> see any issues related to i2c-hid, so those 3 commits might not be the
> culprits.
>
>
>>
>> Please let me know what additional data is needed.
>
> Can you do a bisect between v6.17.7 and v6.17.6?
>
> Cheers,
> Benjamin
>
>>
>> Thank you,
>> Vijay.
>
>
>
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: qcom: milos-fairphone-fp6: Add vibrator support
From: Konrad Dybcio @ 2025-12-04 13:45 UTC (permalink / raw)
To: David Heidelberg, Griffin Kroah-Hartman, Dmitry Torokhov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <9794dcce-0c1d-4c30-8d07-47c50548b4c1@ixit.cz>
On 12/4/25 2:43 PM, David Heidelberg wrote:
> On 04/12/2025 14:34, Konrad Dybcio wrote:
>> On 12/4/25 1:29 PM, Griffin Kroah-Hartman wrote:
>>> Add the required node for haptic playback (Awinic AW86938)
>>>
>>> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
>>> ---
>>> arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 17 +++++++++++++++++
>>
>> The DTS is unfortunately still not merged :/
>>
>> Please arrange with Luca and either squash this into the resubmission
>> (depending on how the driver changes go for the vibrator) or resend it
>> afterwards
>
> would be enough to provide dependency on the Luca patchset trough the amazing
>
> b4 prep --edit-deps
>
> here?
This makes sense for patches that are predicted to be merged without
obstacles - IIRC Luca's original series still may have some dependencies
on various subsystem maintainers for oneliner compatibles
Konrad
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: qcom: milos-fairphone-fp6: Add vibrator support
From: David Heidelberg @ 2025-12-04 13:43 UTC (permalink / raw)
To: Konrad Dybcio, Griffin Kroah-Hartman, Dmitry Torokhov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <bc89b3ac-242f-4890-9996-060c4a0f2b67@oss.qualcomm.com>
On 04/12/2025 14:34, Konrad Dybcio wrote:
> On 12/4/25 1:29 PM, Griffin Kroah-Hartman wrote:
>> Add the required node for haptic playback (Awinic AW86938)
>>
>> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
>> ---
>> arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 17 +++++++++++++++++
>
> The DTS is unfortunately still not merged :/
>
> Please arrange with Luca and either squash this into the resubmission
> (depending on how the driver changes go for the vibrator) or resend it
> afterwards
would be enough to provide dependency on the Luca patchset trough the
amazing
b4 prep --edit-deps
here?
David
>
>> 1 file changed, 17 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> index 0a758fb7f4d413a84cdae695c38616fc6075db67..8c43bc9c1d8312f22ad0aeed84b23d52910e0ca6 100644
>> --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> @@ -717,6 +717,16 @@ vreg_l7p: ldo7 {
>>
>> /* VL53L3 ToF @ 0x29 */
>> /* AW86938FCR vibrator @ 0x5a */
>
> You can remove this comment now
>
> The remainder of the patch lgtm
>
> Konrad
>
--
David Heidelberg
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: qcom: milos-fairphone-fp6: Add vibrator support
From: Konrad Dybcio @ 2025-12-04 13:34 UTC (permalink / raw)
To: Griffin Kroah-Hartman, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20251204-aw86938-driver-v1-3-ebd71868df3a@fairphone.com>
On 12/4/25 1:29 PM, Griffin Kroah-Hartman wrote:
> Add the required node for haptic playback (Awinic AW86938)
>
> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
> ---
> arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 17 +++++++++++++++++
The DTS is unfortunately still not merged :/
Please arrange with Luca and either squash this into the resubmission
(depending on how the driver changes go for the vibrator) or resend it
afterwards
> 1 file changed, 17 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
> index 0a758fb7f4d413a84cdae695c38616fc6075db67..8c43bc9c1d8312f22ad0aeed84b23d52910e0ca6 100644
> --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
> +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
> @@ -717,6 +717,16 @@ vreg_l7p: ldo7 {
>
> /* VL53L3 ToF @ 0x29 */
> /* AW86938FCR vibrator @ 0x5a */
You can remove this comment now
The remainder of the patch lgtm
Konrad
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: input: Add Awinic AW86938
From: Krzysztof Kozlowski @ 2025-12-04 13:09 UTC (permalink / raw)
To: Griffin Kroah-Hartman, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20251204-aw86938-driver-v1-1-ebd71868df3a@fairphone.com>
On 04/12/2025 13:29, Griffin Kroah-Hartman wrote:
> Add bindings for the Awinic AW86938 haptic chip which can be found in
> smartphones.
>
> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
> ---
> Documentation/devicetree/bindings/input/awinic,aw86927.yaml | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
> index b7252916bd727486c1a98913d4ec3ef12422e4bd..c3dee660422192720da3cf63851cea27db819742 100644
> --- a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
> +++ b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
> @@ -11,7 +11,9 @@ maintainers:
>
> properties:
> compatible:
> - const: awinic,aw86927
> + enum:
> + - awinic,aw86927
> + - awinic,aw86938
Your driver change suggests these are compatible, so please express it
here with compatibility and fallback (see exampe-schema or most of other
bindings) or explain in commit msg why devices are not compatible.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 3/3] arm64: dts: qcom: milos-fairphone-fp6: Add vibrator support
From: Griffin Kroah-Hartman @ 2025-12-04 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
Griffin Kroah-Hartman
In-Reply-To: <20251204-aw86938-driver-v1-0-ebd71868df3a@fairphone.com>
Add the required node for haptic playback (Awinic AW86938)
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
---
arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
index 0a758fb7f4d413a84cdae695c38616fc6075db67..8c43bc9c1d8312f22ad0aeed84b23d52910e0ca6 100644
--- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
+++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
@@ -717,6 +717,16 @@ vreg_l7p: ldo7 {
/* VL53L3 ToF @ 0x29 */
/* AW86938FCR vibrator @ 0x5a */
+ vibrator@5a {
+ compatible = "awinic,aw86938";
+ reg = <0x5a>;
+
+ interrupts-extended = <&tlmm 80 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>;
+
+ pinctrl-0 = <&aw86938_int_default>;
+ pinctrl-names = "default";
+ };
};
&ipa {
@@ -907,6 +917,13 @@ sdc2_card_det_n: sdc2-card-det-state {
bias-pull-up;
};
+ aw86938_int_default: aw86938-int-default-state {
+ pins = "gpio80";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
pm8008_int_default: pm8008-int-default-state {
pins = "gpio125";
function = "gpio";
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] Input: aw86938 - add driver for Awinic AW86938
From: Griffin Kroah-Hartman @ 2025-12-04 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
Griffin Kroah-Hartman
In-Reply-To: <20251204-aw86938-driver-v1-0-ebd71868df3a@fairphone.com>
Add support for the I2C-connected Awinic AW86938 LRA haptic driver.
This driver is functionally similar to the AW86927. but suffers from
distortion with higher gain values.
Its vendor driver sets this value to 0x45, which fixes the problem and
does not noticeably effect the AW86927's playback.
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
---
drivers/input/misc/aw86927.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c
index abd117bb309478b3049f74e53582f06989f74e90..39e22dbdeeb7494ba1a8d4ca8fc40b5580c304f9 100644
--- a/drivers/input/misc/aw86927.c
+++ b/drivers/input/misc/aw86927.c
@@ -166,6 +166,7 @@
#define AW86927_BASEADDRH_VAL 0x08
#define AW86927_BASEADDRL_VAL 0x00
+#define AW86938_CHIPID 0x9380
enum aw86927_work_mode {
AW86927_STANDBY_MODE,
AW86927_RAM_MODE,
@@ -372,7 +373,7 @@ static int aw86927_play_sine(struct aw86927_data *haptics)
return err;
/* set gain to value lower than 0x80 to avoid distorted playback */
- err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
+ err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x45);
if (err)
return err;
@@ -602,6 +603,9 @@ static int aw86927_ram_init(struct aw86927_data *haptics)
FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
AW86927_SYSCTRL3_EN_RAMINIT_ON));
+ /* AW86938 wants a 1ms delay here */
+ usleep_range(1000, 1500);
+
/* Set base address for the start of the SRAM waveforms */
err = regmap_write(haptics->regmap,
AW86927_BASEADDRH_REG,
@@ -724,7 +728,12 @@ static int aw86927_detect(struct aw86927_data *haptics)
chip_id = be16_to_cpu(read_buf);
- if (chip_id != AW86927_CHIPID) {
+ switch (chip_id) {
+ case AW86927_CHIPID:
+ break;
+ case AW86938_CHIPID:
+ break;
+ default:
dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
return -ENODEV;
}
@@ -834,6 +843,7 @@ static int aw86927_probe(struct i2c_client *client)
static const struct of_device_id aw86927_of_id[] = {
{ .compatible = "awinic,aw86927" },
+ { .compatible = "awinic,aw86938" },
{ /* sentinel */ }
};
--
2.43.0
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: input: Add Awinic AW86938
From: Griffin Kroah-Hartman @ 2025-12-04 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
Griffin Kroah-Hartman
In-Reply-To: <20251204-aw86938-driver-v1-0-ebd71868df3a@fairphone.com>
Add bindings for the Awinic AW86938 haptic chip which can be found in
smartphones.
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
---
Documentation/devicetree/bindings/input/awinic,aw86927.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
index b7252916bd727486c1a98913d4ec3ef12422e4bd..c3dee660422192720da3cf63851cea27db819742 100644
--- a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
+++ b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml
@@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
- const: awinic,aw86927
+ enum:
+ - awinic,aw86927
+ - awinic,aw86938
reg:
maxItems: 1
--
2.43.0
^ permalink raw reply related
* [PATCH 0/3] Add support for Awinic AW86938 haptic driver
From: Griffin Kroah-Hartman @ 2025-12-04 12:28 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Luca Weiss
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
Griffin Kroah-Hartman
Add devicetree bindings and a driver for the AW86938 haptic driver chip,
and add it to the devicetree for the Fairphone 6 smartphone.
This driver is very similar to the AW86927, and shares many core
features.
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
---
Griffin Kroah-Hartman (3):
dt-bindings: input: Add Awinic AW86938
Input: aw86938 - add driver for Awinic AW86938
arm64: dts: qcom: milos-fairphone-fp6: Add vibrator support
.../devicetree/bindings/input/awinic,aw86927.yaml | 4 +++-
arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 17 +++++++++++++++++
drivers/input/misc/aw86927.c | 14 ++++++++++++--
3 files changed, 32 insertions(+), 3 deletions(-)
---
base-commit: 1cc3747c5a6764ddc6b2d1d8fadb654493ac4ea0
change-id: 20251113-aw86938-driver-b4fa0d3228a2
Best regards,
--
Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
^ permalink raw reply
* [PATCH] Input: pf1550 - convert to DEFINE_SIMPLE_DEV_PM_OPS
From: Arnd Bergmann @ 2025-12-04 10:04 UTC (permalink / raw)
To: Samuel Kayode, Dmitry Torokhov, Frank Li, Lee Jones
Cc: Arnd Bergmann, imx, linux-input, linux-kernel
From: Arnd Bergmann <arnd@arndb.de>
SIMPLE_DEV_PM_OPS() is deprecated and used incorrectly in this new
driver:
drivers/input/misc/pf1550-onkey.c:154:12: error: 'pf1550_onkey_resume' defined but not used [-Werror=unused-function]
154 | static int pf1550_onkey_resume(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~
drivers/input/misc/pf1550-onkey.c:133:12: error: 'pf1550_onkey_suspend' defined but not used [-Werror=unused-function]
133 | static int pf1550_onkey_suspend(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~~
Convert to the modern DEFINE_SIMPLE_DEV_PM_OPS() that avoids these warnings.
Fixes: 9acb215cbebd ("Input: pf1550 - add onkey support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/input/misc/pf1550-onkey.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c
index 9be6377151cb..a636ceedfc04 100644
--- a/drivers/input/misc/pf1550-onkey.c
+++ b/drivers/input/misc/pf1550-onkey.c
@@ -173,8 +173,8 @@ static int pf1550_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
- pf1550_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
+ pf1550_onkey_resume);
static const struct platform_device_id pf1550_onkey_id[] = {
{ "pf1550-onkey", },
--
2.39.5
^ permalink raw reply related
* Re: [PATCH] HID: validate report length and constants
From: Benjamin Tissoires @ 2025-12-04 9:53 UTC (permalink / raw)
To: Davide Beatrici
Cc: Terry Junge, linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <9e44de7bab6967a200d7404ebb068071@davidebeatrici.dev>
On Dec 02 2025, Davide Beatrici wrote:
> > Can you supply the Device, Configuration, and Report Descriptors?
>
> Sure.
>
> Device Descriptor:
> idVendor 0x373b Compx
> idProduct 0x1107 ATK X1 SE Nearlink
> bcdDevice 1.21
> bcdUSB 2.00
> bMaxPacketSize0 64
> iManufacturer 1 Compx
> iProduct 2 ATK X1 SE Nearlink
> bNumConfigurations 1
>
> Configuration Descriptor:
> wTotalLength 0x0054
> bNumInterfaces 3
> bmAttributes 0xa0 (Bus Powered, Remote Wakeup)
> MaxPower 494mA
>
> Interface 0: HID Keyboard
> HID Descriptor: wDescriptorLength 77
> Endpoint IN 0x81, Interrupt, 64 bytes
>
> Interface 1: HID (non‑boot)
> HID Descriptor: wDescriptorLength 156
> Endpoint IN 0x82, Interrupt, 64 bytes
>
> Interface 2: HID Mouse
> HID Descriptor: wDescriptorLength 87
> Endpoint IN 0x83, Interrupt, 64 bytes
>
> Report Descriptors:
>
> Interface 2 (Mouse):
> 05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 05
> 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01
> 05 01 09 30 09 31 16 00 80 26 FF 7F 75 10 95 02
> 81 06 C0 A1 00 05 01 09 38 15 81 25 7F 75 08 95
> 01 81 06 C0 A1 00 05 0C 0A 38 02 95 01 75 08 15
> 81 25 7F 81 06 C0 C0
>
> Interface 1 (HID composite):
> 05 0C 09 01 A1 01 85 05 15 00 26 14 05 19 00 2A
> 14 05 75 10 95 01 81 00 C0 05 01 09 80 A1 01 85
> 03 19 81 29 83 15 00 25 01 95 03 75 01 81 02 95
> 01 75 05 81 01 C0 05 01 09 06 A1 01 85 04 05 07
> 15 00 25 01 19 00 29 9F 95 A0 75 01 81 02 C0 06
> 02 FF 09 02 A1 01 85 13 15 00 26 FF 00 75 08 95
> 13 09 02 81 00 09 02 91 00 C0 06 02 FF 09 02 A1
> 01 85 08 15 00 26 FF 00 75 08 95 10 09 02 81 00
> 09 02 91 00 C0 06 04 FF 09 02 A1 01 85 06 09 02
> 15 00 26 FF 00 75 08 95 07 B1 02 C0
>
> Interface 0 (Keyboard):
> 05 01 09 06 A1 01 05 08 19 01 29 03 15 00 25 01
> 75 01 95 03 91 02 95 05 91 01 05 07 19 E0 29 E7
> 15 00 25 01 75 01 95 08 81 02 75 08 95 01 81 01
> 05 07 19 00 2A FF 00 15 00 26 FF 00 75 08 95 05
> 81 00 05 FF 09 03 75 08 95 01 81 02 C0
Thanks for the logs.
So after analysing the wireshark capture and these, the problem is that
the device sends a USB report of length 1 on the keyboard interface when
we should actually get one of size 8.
However, the device also shows an output report of size 1, but it is not
supposed to send it as an input report. I wonder if the firmware bug is
not that it tries to give the host the current state of its output
report at plug (which is wrong but Windows must be papering over it).
Anyway couple of observations:
- the URB is of size 1, so the fact that the constant field is not 0
means that we are just reading random memory at offset 1 in the
provided data, so you might have a chance that it eventually becomes 0
- the fix should be focusing on the length of the provided report, not
on the content. However, in hid_report_raw_event(), just before you
inserted your call to your hid_validate_report(), there is already a
check on the length of the report which memsets to 0 the rest of the
buffer. This seems a little bit optimistic if the provided buffer from
USB is exactly the size of the provided "size" argument.
But then, why would you get random data in the const fields if there
is a memset if the provided length is "1"?
So, can you add a printk before your call to hid_validate_report() to
show the provided "size" argument (csize), or just enable the hid_dbg()
trace output which should tell us if we enter that test and do the
memset (which I suppose we are not).
Cheers,
Benjamin
^ permalink raw reply
* RE: [PATCH] HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value
From: Xu, Even @ 2025-12-04 1:09 UTC (permalink / raw)
To: Thomas Fourier
Cc: Sun, Xinpeng, Jiri Kosina, Benjamin Tissoires, Andy Shevchenko,
Mark Pearson, Srinivas Pandruvada, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20251203165651.69215-2-fourier.thomas@gmail.com>
> -----Original Message-----
> From: Thomas Fourier <fourier.thomas@gmail.com>
> Sent: Thursday, December 4, 2025 12:57 AM
> Cc: Thomas Fourier <fourier.thomas@gmail.com>; Xu, Even
> <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>; Jiri Kosina
> <jikos@kernel.org>; Benjamin Tissoires <bentiss@kernel.org>; Andy Shevchenko
> <andriy.shevchenko@linux.intel.com>; Mark Pearson <mpearson-
> lenovo@squebb.ca>; Srinivas Pandruvada
> <srinivas.pandruvada@linux.intel.com>; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: [PATCH] HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value
>
> The `dma_unmap_sg()` functions should be called with the same nents as the
> `dma_map_sg()`, not the value the map function returned.
>
> Save the number of entries in struct thc_dma_configuration.
>
> Fixes: a688404b2e20 ("HID: intel-thc-hid: intel-thc: Add THC DMA interfaces")
> Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
Thanks for the fix!
Looks good to me.
Reviewed-by: Even Xu <even.xu@intel.com>
> ---
> drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c | 4 +++- drivers/hid/intel-thc-
> hid/intel-thc/intel-thc-dma.h | 2 ++
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-
> thc-hid/intel-thc/intel-thc-dma.c
> index 82b8854843e0..a0c368aa7979 100644
> --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
> +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
> @@ -232,6 +232,7 @@ static int setup_dma_buffers(struct thc_device *dev,
> return 0;
>
> memset(config->sgls, 0, sizeof(config->sgls));
> + memset(config->sgls_nent_pages, 0, sizeof(config->sgls_nent_pages));
> memset(config->sgls_nent, 0, sizeof(config->sgls_nent));
>
> cpu_addr = dma_alloc_coherent(dev->dev, prd_tbls_size, @@ -254,6
> +255,7 @@ static int setup_dma_buffers(struct thc_device *dev,
> }
> count = dma_map_sg(dev->dev, config->sgls[i], nent, dir);
>
> + config->sgls_nent_pages[i] = nent;
> config->sgls_nent[i] = count;
> }
>
> @@ -299,7 +301,7 @@ static void release_dma_buffers(struct thc_device *dev,
> continue;
>
> dma_unmap_sg(dev->dev, config->sgls[i],
> - config->sgls_nent[i],
> + config->sgls_nent_pages[i],
> config->dir);
>
> sgl_free(config->sgls[i]);
> diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h b/drivers/hid/intel-
> thc-hid/intel-thc/intel-thc-dma.h
> index 78917400492c..541d33995baf 100644
> --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
> +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
> @@ -91,6 +91,7 @@ struct thc_prd_table {
> * @dir: Direction of DMA for this config
> * @prd_tbls: PRD tables for current DMA
> * @sgls: Array of pointers to scatter-gather lists
> + * @sgls_nent_pages: Number of pages per scatter-gather list
> * @sgls_nent: Actual number of entries per scatter-gather list
> * @prd_tbl_num: Actual number of PRD tables
> * @max_packet_size: Size of the buffer needed for 1 DMA message (1 PRD
> table) @@ -107,6 +108,7 @@ struct thc_dma_configuration {
>
> struct thc_prd_table *prd_tbls;
> struct scatterlist *sgls[PRD_TABLES_NUM];
> + u8 sgls_nent_pages[PRD_TABLES_NUM];
> u8 sgls_nent[PRD_TABLES_NUM];
> u8 prd_tbl_num;
>
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH] HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value
From: Andy Shevchenko @ 2025-12-03 17:02 UTC (permalink / raw)
To: Thomas Fourier
Cc: Even Xu, Xinpeng Sun, Jiri Kosina, Benjamin Tissoires,
Mark Pearson, Srinivas Pandruvada, linux-input, linux-kernel
In-Reply-To: <20251203165651.69215-2-fourier.thomas@gmail.com>
On Wed, Dec 03, 2025 at 05:56:35PM +0100, Thomas Fourier wrote:
> The `dma_unmap_sg()` functions should be called with the same nents as the
> `dma_map_sg()`, not the value the map function returned.
>
> Save the number of entries in struct thc_dma_configuration.
Your email has an empty To:. Some spamfilters may be triggered by this.
I recommend to use `b4` tool to handle the patches.
The change LGTM,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH] HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value
From: Thomas Fourier @ 2025-12-03 16:56 UTC (permalink / raw)
Cc: Thomas Fourier, Even Xu, Xinpeng Sun, Jiri Kosina,
Benjamin Tissoires, Andy Shevchenko, Mark Pearson,
Srinivas Pandruvada, linux-input, linux-kernel
The `dma_unmap_sg()` functions should be called with the same nents as the
`dma_map_sg()`, not the value the map function returned.
Save the number of entries in struct thc_dma_configuration.
Fixes: a688404b2e20 ("HID: intel-thc-hid: intel-thc: Add THC DMA interfaces")
Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
---
drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c | 4 +++-
drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h | 2 ++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
index 82b8854843e0..a0c368aa7979 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
@@ -232,6 +232,7 @@ static int setup_dma_buffers(struct thc_device *dev,
return 0;
memset(config->sgls, 0, sizeof(config->sgls));
+ memset(config->sgls_nent_pages, 0, sizeof(config->sgls_nent_pages));
memset(config->sgls_nent, 0, sizeof(config->sgls_nent));
cpu_addr = dma_alloc_coherent(dev->dev, prd_tbls_size,
@@ -254,6 +255,7 @@ static int setup_dma_buffers(struct thc_device *dev,
}
count = dma_map_sg(dev->dev, config->sgls[i], nent, dir);
+ config->sgls_nent_pages[i] = nent;
config->sgls_nent[i] = count;
}
@@ -299,7 +301,7 @@ static void release_dma_buffers(struct thc_device *dev,
continue;
dma_unmap_sg(dev->dev, config->sgls[i],
- config->sgls_nent[i],
+ config->sgls_nent_pages[i],
config->dir);
sgl_free(config->sgls[i]);
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
index 78917400492c..541d33995baf 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
@@ -91,6 +91,7 @@ struct thc_prd_table {
* @dir: Direction of DMA for this config
* @prd_tbls: PRD tables for current DMA
* @sgls: Array of pointers to scatter-gather lists
+ * @sgls_nent_pages: Number of pages per scatter-gather list
* @sgls_nent: Actual number of entries per scatter-gather list
* @prd_tbl_num: Actual number of PRD tables
* @max_packet_size: Size of the buffer needed for 1 DMA message (1 PRD table)
@@ -107,6 +108,7 @@ struct thc_dma_configuration {
struct thc_prd_table *prd_tbls;
struct scatterlist *sgls[PRD_TABLES_NUM];
+ u8 sgls_nent_pages[PRD_TABLES_NUM];
u8 sgls_nent[PRD_TABLES_NUM];
u8 prd_tbl_num;
--
2.43.0
^ permalink raw reply related
* [PATCH v2] HID: multitouch: add quirks for Lenovo Yoga Book 9i
From: Brian Howard @ 2025-12-03 2:35 UTC (permalink / raw)
To: jikos
Cc: Brian Howard, Kris Fredrick, Andrei Shumailov, Benjamin Tissoires,
linux-input, linux-kernel
In-Reply-To: <6243251s-2rp7-7092-r489-1n4531qn0826@xreary.bet>
The Lenovo Yoga Book 9i is a dual-screen laptop, with a single composite
USB device providing both touch and tablet interfaces for both screens.
All inputs report through a single device, differentiated solely by report
numbers. As there is no way for udev to differentiate the inputs based on
USB vendor/product ID or interface numbers, custom naming is required to
match against for downstream configuration. A firmware bug also results
in an erroneous InRange message report being received after the stylus
leaves proximity, blocking later touch events. Add required quirks for
Gen 8 to Gen 10 models, including a new quirk providing for custom input
device naming and dropping erroneous InRange reports.
Signed-off-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Kris Fredrick <linux.baguette800@slmail.me>
Reported-by: Andrei Shumailov <gentoo1993@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220386
---
V1->V2 Changes:
- Changed definition of f and i varliables to the loop scope.
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-multitouch.c | 72 ++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0723b4b1c9ec..e896a6310bb2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -833,6 +833,7 @@
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
+#define USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 179dc316b4b5..4b3e7c212a48 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
+#define MT_QUIRK_YOGABOOK9I BIT(24)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -229,6 +230,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
#define MT_CLS_APPLE_TOUCHBAR 0x0114
+#define MT_CLS_YOGABOOK9I 0x0115
#define MT_CLS_SIS 0x0457
#define MT_DEFAULT_MAXCONTACT 10
@@ -424,6 +426,14 @@ static const struct mt_class mt_classes[] = {
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE,
+ },
+ { .name = MT_CLS_YOGABOOK9I,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_FORCE_MULTI_INPUT |
+ MT_QUIRK_SEPARATE_APP_REPORT |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_YOGABOOK9I,
+ .export_all_inputs = true
},
{ }
};
@@ -1565,6 +1575,38 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
if (rdata && rdata->is_mt_collection)
return mt_touch_report(hid, rdata);
+ /* Lenovo Yoga Book 9i requires consuming and dropping certain bogus reports */
+ if (rdata && rdata->application &&
+ (rdata->application->quirks & MT_QUIRK_YOGABOOK9I)) {
+
+ bool all_zero_report = true;
+
+ for (int f = 0; f < report->maxfield && all_zero_report; f++) {
+ struct hid_field *fld = report->field[f];
+
+ for (int i = 0; i < fld->report_count; i++) {
+ unsigned int usage = fld->usage[i].hid;
+
+ if (usage == HID_DG_INRANGE ||
+ usage == HID_DG_TIPSWITCH ||
+ usage == HID_DG_BARRELSWITCH ||
+ usage == HID_DG_BARRELSWITCH2 ||
+ usage == HID_DG_CONTACTID ||
+ usage == HID_DG_TILT_X ||
+ usage == HID_DG_TILT_Y) {
+
+ if (fld->value[i] != 0) {
+ all_zero_report = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (all_zero_report)
+ return;
+ }
+
if (field && field->hidinput && field->hidinput->input)
input_sync(field->hidinput->input);
}
@@ -1761,6 +1803,30 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
break;
}
+ /* Lenovo Yoga Book 9i requires custom naming to allow differentiation in udev */
+ if (hi->report && td->mtclass.quirks & MT_QUIRK_YOGABOOK9I) {
+ switch (hi->report->id) {
+ case 48:
+ suffix = "Touchscreen Top";
+ break;
+ case 56:
+ suffix = "Touchscreen Bottom";
+ break;
+ case 20:
+ suffix = "Stylus Top";
+ break;
+ case 40:
+ suffix = "Stylus Bottom";
+ break;
+ case 80:
+ suffix = "Emulated Touchpad";
+ break;
+ default:
+ suffix = "";
+ break;
+ }
+ }
+
if (suffix) {
hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
"%s %s", hdev->name, suffix);
@@ -2266,6 +2332,12 @@ static const struct hid_device_id mt_devices[] = {
USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X12_TAB2) },
+ /* Lenovo Yoga Book 9i */
+ { .driver_data = MT_CLS_YOGABOOK9I,
+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_LENOVO,
+ USB_DEVICE_ID_LENOVO_YOGABOOK9I) },
+
/* Logitech devices */
{ .driver_data = MT_CLS_NSMU,
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,
--
2.49.0
^ permalink raw reply related
* Re: [PATCH] HID: validate report length and constants
From: Davide Beatrici @ 2025-12-02 21:54 UTC (permalink / raw)
To: Terry Junge
Cc: Benjamin Tissoires, linux-kernel, linux-input, jikos,
benjamin.tissoires
In-Reply-To: <91117308-7eb5-4258-ac87-1afb2d46d2b5@cosmicgizmosystems.com>
> Can you supply the Device, Configuration, and Report Descriptors?
Sure.
Device Descriptor:
idVendor 0x373b Compx
idProduct 0x1107 ATK X1 SE Nearlink
bcdDevice 1.21
bcdUSB 2.00
bMaxPacketSize0 64
iManufacturer 1 Compx
iProduct 2 ATK X1 SE Nearlink
bNumConfigurations 1
Configuration Descriptor:
wTotalLength 0x0054
bNumInterfaces 3
bmAttributes 0xa0 (Bus Powered, Remote Wakeup)
MaxPower 494mA
Interface 0: HID Keyboard
HID Descriptor: wDescriptorLength 77
Endpoint IN 0x81, Interrupt, 64 bytes
Interface 1: HID (non‑boot)
HID Descriptor: wDescriptorLength 156
Endpoint IN 0x82, Interrupt, 64 bytes
Interface 2: HID Mouse
HID Descriptor: wDescriptorLength 87
Endpoint IN 0x83, Interrupt, 64 bytes
Report Descriptors:
Interface 2 (Mouse):
05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 05
15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01
05 01 09 30 09 31 16 00 80 26 FF 7F 75 10 95 02
81 06 C0 A1 00 05 01 09 38 15 81 25 7F 75 08 95
01 81 06 C0 A1 00 05 0C 0A 38 02 95 01 75 08 15
81 25 7F 81 06 C0 C0
Interface 1 (HID composite):
05 0C 09 01 A1 01 85 05 15 00 26 14 05 19 00 2A
14 05 75 10 95 01 81 00 C0 05 01 09 80 A1 01 85
03 19 81 29 83 15 00 25 01 95 03 75 01 81 02 95
01 75 05 81 01 C0 05 01 09 06 A1 01 85 04 05 07
15 00 25 01 19 00 29 9F 95 A0 75 01 81 02 C0 06
02 FF 09 02 A1 01 85 13 15 00 26 FF 00 75 08 95
13 09 02 81 00 09 02 91 00 C0 06 02 FF 09 02 A1
01 85 08 15 00 26 FF 00 75 08 95 10 09 02 81 00
09 02 91 00 C0 06 04 FF 09 02 A1 01 85 06 09 02
15 00 26 FF 00 75 08 95 07 B1 02 C0
Interface 0 (Keyboard):
05 01 09 06 A1 01 05 08 19 01 29 03 15 00 25 01
75 01 95 03 91 02 95 05 91 01 05 07 19 E0 29 E7
15 00 25 01 75 01 95 08 81 02 75 08 95 01 81 01
05 07 19 00 2A FF 00 15 00 26 FF 00 75 08 95 05
81 00 05 FF 09 03 75 08 95 01 81 02 C0
^ permalink raw reply
* Re: [PATCH] HID: validate report length and constants
From: Terry Junge @ 2025-12-02 21:40 UTC (permalink / raw)
To: Davide Beatrici, Benjamin Tissoires
Cc: linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <a7d352dd1d310bf07263106f2ce0f8ed@davidebeatrici.dev>
On 12/2/25 11:41 AM, Davide Beatrici wrote:
> Thank you very much for your feedback!
>
> I can send you a new identical device for testing if you would like.
>
Can you supply the Device, Configuration, and Report Descriptors?
Thanks,
Terry
>> Can you show us what packets are emitted?
>>
>> If it's a firmware bug, we better have a specific driver for it could
>> be a HID-BPF program that just filters out the unwanted reports.
>>
>> Also, how does Windows behave with this mouse? Does it need a special
>> driver?
>
> Sorry, I should've mentioned the malformed packet also shows up on Windows,
> but is seemingly ignored because there appear to be no side effects whatsoever.
>
> No special driver needed, it's detected as a standard HID mouse.
>
> WireShark capture:
> https://dl.houseof.software/misc/atk_x1_se_malformed_packet.pcapng
>
> Packet screenshot:
> https://dl.houseof.software/misc/atk_x1_se_malformed_packet.png
>
>> Looks like there is something wrong either in the report descriptor of
>> this mouse, either in the emitted reports.
>
> Definitely. I have already informed the manufacturer, who confirmed the mouse
> has only been tested on Windows.
>
> My inquiry was forwarded to their R&D team, hopefully a firmware update will
> be released soon.
>
>> Yep, this is on purpose because Miscrosoft's own driver works that way
>> and many HID devices do not bother to mark the non constant bits as
>> data. So if you enforce the spec here, you'll break a numerous of
>> devices unfortunatelly.
>
>> Ouch. If I read you correctly, you are rejecting the entire report if a
>> constant field is not 0. It is common for constant fields to be just
>> garbage (whatever is in the memory, because writing firmware is hard),
>> so even if we were to accept this patch, this would break even more
>> devices :(
>
>> I am pretty sure the HID selftests will fail with this patch applied,
>> because there are probably a couple of devices there with the "non
>> constant" behaviour.
>
> Oh, in that case let's just drop that part from the patch, since it's
> actually not altering the behavior with this specific device.
>
> The malformed packet is detected and rejected by two checks:
>
> Malformed report: raw_len=1 payload_len=1 expected=8 (ID 0)
> Malformed report: const slice OOB (bit_off 8, len 8)
>
^ permalink raw reply
* Re: [PATCH] HID: validate report length and constants
From: Davide Beatrici @ 2025-12-02 19:41 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <xyh6scqrfzft3hhmqowyverzezb2xsmsexegk3sydyfbiknba4@6sy3qbtsinrr>
Thank you very much for your feedback!
I can send you a new identical device for testing if you would like.
> Can you show us what packets are emitted?
>
> If it's a firmware bug, we better have a specific driver for it could
> be a HID-BPF program that just filters out the unwanted reports.
>
> Also, how does Windows behave with this mouse? Does it need a special
> driver?
Sorry, I should've mentioned the malformed packet also shows up on
Windows,
but is seemingly ignored because there appear to be no side effects
whatsoever.
No special driver needed, it's detected as a standard HID mouse.
WireShark capture:
https://dl.houseof.software/misc/atk_x1_se_malformed_packet.pcapng
Packet screenshot:
https://dl.houseof.software/misc/atk_x1_se_malformed_packet.png
> Looks like there is something wrong either in the report descriptor of
> this mouse, either in the emitted reports.
Definitely. I have already informed the manufacturer, who confirmed the
mouse
has only been tested on Windows.
My inquiry was forwarded to their R&D team, hopefully a firmware update
will
be released soon.
> Yep, this is on purpose because Miscrosoft's own driver works that way
> and many HID devices do not bother to mark the non constant bits as
> data. So if you enforce the spec here, you'll break a numerous of
> devices unfortunatelly.
> Ouch. If I read you correctly, you are rejecting the entire report if a
> constant field is not 0. It is common for constant fields to be just
> garbage (whatever is in the memory, because writing firmware is hard),
> so even if we were to accept this patch, this would break even more
> devices :(
> I am pretty sure the HID selftests will fail with this patch applied,
> because there are probably a couple of devices there with the "non
> constant" behaviour.
Oh, in that case let's just drop that part from the patch, since it's
actually not altering the behavior with this specific device.
The malformed packet is detected and rejected by two checks:
Malformed report: raw_len=1 payload_len=1 expected=8 (ID 0)
Malformed report: const slice OOB (bit_off 8, len 8)
^ permalink raw reply
* Re: [PATCH v8 1/2] Input: add ABS_SND_PROFILE
From: Pavel Machek @ 2025-12-02 12:18 UTC (permalink / raw)
To: david
Cc: Dmitry Torokhov, Jonathan Corbet, Jiri Kosina, Benjamin Tissoires,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Casey Connolly, Guido Günther, linux-input,
linux-doc, linux-kernel, linux-arm-msm, devicetree, phone-devel,
Gergo Koteles
In-Reply-To: <20251113-op6-tri-state-v8-1-54073f3874bc@ixit.cz>
[-- Attachment #1: Type: text/plain, Size: 879 bytes --]
On Thu 2025-11-13 17:02:58, David Heidelberg via B4 Relay wrote:
> From: Gergo Koteles <soyer@irl.hu>
>
> ABS_SND_PROFILE used to describe the state of a multi-value sound profile
> switch. This will be used for the alert-slider on OnePlus phones or other
> phones.
>
> Profile values added as SND_PROFLE_(SILENT|VIBRATE|RING) identifiers
> to input-event-codes.h so they can be used from DTS.
>
> Signed-off-by: Gergo Koteles <soyer@irl.hu>
> Reviewed-by: Bjorn Andersson <andersson@kernel.org>
> Tested-by: Guido Günther <agx@sigxcpu.org> # oneplus,fajita & oneplus,enchilada
> Reviewed-by: Guido Günther <agx@sigxcpu.org>
> Signed-off-by: David Heidelberg <david@ixit.cz>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Best regards,
Pavel
--
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox