* [PATCH v8 0/2] Add support for Wacom W9000-series penabled touchscreens
@ 2026-05-28 7:48 Hendrik Noack
2026-05-28 7:48 ` [PATCH v8 1/2] dt-bindings: Input: Add " Hendrik Noack
2026-05-28 7:48 ` [PATCH v8 2/2] Input: Add support for " Hendrik Noack
0 siblings, 2 replies; 5+ messages in thread
From: Hendrik Noack @ 2026-05-28 7:48 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, Ferass El Hafidi, 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 W9002 and
W9007A, which I or Ferass could test on 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.
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)
---
Changes in v4:
- adopt to feedback (thanks dmitry.torokhov@gmail.com)
- add W9002 support (thanks funderscore@postmarketos.org)
- add reset-gpios, necessary for some chips
- remove R-b from krzk due to changes in dt-bindings
---
Changes in v5:
- adopt dt-bindings format to suggestion (thanks krzk@kernel.org)
- remove pen-inserted functionality as suggested (thanks dmitry.torokhov@gmail.com)
---
Changes in v6:
- add info on difference between variants
- add A-b from conor
- add warning for out of range pressure
---
Changes in v7:
- address feedback of sashiko (thanks dmitry.torokhov@gmail.com)
---
Changes in v8:
- add regulator and interrupt headers explicitely
- adjust some data types
---
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 | 73 +++
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/wacom_w9000.c | 448 ++++++++++++++++++
4 files changed, 534 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 [flat|nested] 5+ messages in thread
* [PATCH v8 1/2] dt-bindings: Input: Add Wacom W9000-series penabled touchscreens
2026-05-28 7:48 [PATCH v8 0/2] Add support for Wacom W9000-series penabled touchscreens Hendrik Noack
@ 2026-05-28 7:48 ` Hendrik Noack
2026-05-28 8:32 ` sashiko-bot
2026-05-28 7:48 ` [PATCH v8 2/2] Input: Add support for " Hendrik Noack
1 sibling, 1 reply; 5+ messages in thread
From: Hendrik Noack @ 2026-05-28 7:48 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, Ferass El Hafidi, linux-input, devicetree,
linux-kernel
Add bindings for Wacom W9002 and two Wacom W9007 variants which can be
found in tablets.
W9002, W9007A LT03, and W9007A V1 differ in the length of the return
message containing coordinates, distance, pressure and button status.
Co-developed-by: Ferass El Hafidi <funderscore@postmarketos.org>
Signed-off-by: Ferass El Hafidi <funderscore@postmarketos.org>
Signed-off-by: Hendrik Noack <hendrik-noack@gmx.de>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../input/touchscreen/wacom,w9007a-lt03.yaml | 73 +++++++++++++++++++
1 file changed, 73 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..6d1da6a435d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
@@ -0,0 +1,73 @@
+# 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 controllers in different devices may differ. This can also
+ affect the controller's behavior.
+
+allOf:
+ - $ref: touchscreen.yaml#
+
+properties:
+ compatible:
+ enum:
+ - wacom,w9002
+ - wacom,w9007a-lt03
+ - wacom,w9007a-v1
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply: true
+
+ flash-mode-gpios:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+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>;
+ reset-gpios = <&gpx0 1 GPIO_ACTIVE_LOW>;
+
+ touchscreen-x-mm = <216>;
+ touchscreen-y-mm = <135>;
+ touchscreen-inverted-x;
+ };
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v8 2/2] Input: Add support for Wacom W9000-series penabled touchscreens
2026-05-28 7:48 [PATCH v8 0/2] Add support for Wacom W9000-series penabled touchscreens Hendrik Noack
2026-05-28 7:48 ` [PATCH v8 1/2] dt-bindings: Input: Add " Hendrik Noack
@ 2026-05-28 7:48 ` Hendrik Noack
2026-05-28 9:01 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Hendrik Noack @ 2026-05-28 7:48 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Hendrik Noack, Ferass El Hafidi, linux-input, devicetree,
linux-kernel
Add driver for Wacom W9002 and two Wacom W9007A variants. These are
penabled touchscreens supporting passive Wacom Pens and use I2C.
Co-developed-by: Ferass El Hafidi <funderscore@postmarketos.org>
Signed-off-by: Ferass El Hafidi <funderscore@postmarketos.org>
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 | 448 ++++++++++++++++++++++++
3 files changed, 461 insertions(+)
create mode 100644 drivers/input/touchscreen/wacom_w9000.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 484522d8d675..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
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6d397268d2e3..bfd9de83389d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -100,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/wacom_w9000.c b/drivers/input/touchscreen/wacom_w9000.c
new file mode 100644
index 000000000000..7795508f93b2
--- /dev/null
+++ b/drivers/input/touchscreen/wacom_w9000.c
@@ -0,0 +1,448 @@
+// 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/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;
+ bool powered;
+
+ 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;
+ int error;
+ int retry = 0;
+ u8 data[CMD_QUERY_NUM_MAX];
+
+ for (; 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 || (data[0] != 0x0f))
+ return error ? error : -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", wacom_data->prop.max_x,
+ wacom_data->prop.max_y, wacom_data->max_pressure,
+ wacom_data->fw_version);
+
+ return 0;
+}
+
+/* Must be called with wacom_data->input_dev->mutex held */
+static int wacom_w9000_power_on(struct wacom_w9000_data *wacom_data)
+{
+ int error;
+
+ if (wacom_data->powered)
+ return 0;
+
+ 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);
+
+ wacom_data->powered = true;
+
+ return error;
+}
+
+/* Must be called with wacom_data->input_dev->mutex held */
+static int wacom_w9000_power_off(struct wacom_w9000_data *wacom_data)
+{
+ if (!wacom_data->powered)
+ return 0;
+
+ disable_irq(wacom_data->irq);
+ gpiod_set_value_cansleep(wacom_data->reset_gpio, 1);
+ regulator_disable(wacom_data->regulator);
+
+ wacom_data->powered = false;
+
+ 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 error;
+ u8 data[MSG_COORD_NUM_MAX];
+ bool touch, rubber, side_button;
+ u16 x, y, pressure;
+ u8 distance = 0;
+
+ 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", 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", x, y);
+ return;
+ }
+
+ if (pressure > wacom_data->max_pressure) {
+ dev_warn_ratelimited(dev, "Pressure out of range %d", 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);
+
+ wacom_data->powered = false;
+
+ 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->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);
+
+ 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);
+
+ return wacom_w9000_power_off(wacom_data);
+}
+
+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);
+ else
+ 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 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 [flat|nested] 5+ messages in thread
* Re: [PATCH v8 1/2] dt-bindings: Input: Add Wacom W9000-series penabled touchscreens
2026-05-28 7:48 ` [PATCH v8 1/2] dt-bindings: Input: Add " Hendrik Noack
@ 2026-05-28 8:32 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-05-28 8:32 UTC (permalink / raw)
To: Hendrik Noack; +Cc: robh, dmitry.torokhov, conor+dt, devicetree, linux-input
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Low] Vendor-specific property 'flash-mode-gpios' is missing the vendor prefix.
- [Low] Node name 'digitizer@56' in the example should be a standard generic name such as 'touchscreen@56'.
- [Low] The binding file is named after a specific variant ('wacom,w9007a-lt03.yaml') rather than the first compatible string ('wacom,w9002.yaml').
--
commit d38ecd0efb12cc8efc9000f9c78e8a14387d40c6
Author: Hendrik Noack <hendrik-noack@gmx.de>
Subject: dt-bindings: Input: Add Wacom W9000-series penabled touchscreens
This commit adds bindings for the Wacom W9002, W9007A LT03, and W9007A V1
touchscreen controllers. These controllers differ slightly in their return
message formats.
> 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 0000000000000..6d1da6a435d39
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml
[Severity: Low]
Should this file be named wacom,w9002.yaml after the first compatible string,
rather than being named after a specific variant?
> @@ -0,0 +1,73 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
[ ... ]
> + vdd-supply: true
> +
> + flash-mode-gpios:
> + maxItems: 1
[Severity: Low]
Does this property need a vendor prefix (wacom,flash-mode-gpios) since it is
hardware-specific?
[ ... ]
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + digitizer@56 {
[Severity: Low]
Should this node name be changed to a generic class name such as
touchscreen@56?
> + compatible = "wacom,w9007a-lt03";
> + reg = <0x56>;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260528074818.12151-1-hendrik-noack@gmx.de?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v8 2/2] Input: Add support for Wacom W9000-series penabled touchscreens
2026-05-28 7:48 ` [PATCH v8 2/2] Input: Add support for " Hendrik Noack
@ 2026-05-28 9:01 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-05-28 9:01 UTC (permalink / raw)
To: Hendrik Noack; +Cc: robh, conor+dt, devicetree, dmitry.torokhov, linux-input
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The driver uses stack-allocated buffers for I2C transfers, which violates the DMA API and can cause panics or memory corruption.
--
commit 5c60cba7d031762dd1ed0e3769ce031bf93c9b48
Author: Hendrik Noack <hendrik-noack@gmx.de>
Input: Add support for Wacom W9000-series penabled touchscreens
This commit adds a new input driver for the Wacom W9000-series penabled
touchscreens, supporting passive Wacom pens over an I2C interface.
> diff --git a/drivers/input/touchscreen/wacom_w9000.c b/drivers/input/touchscreen/wacom_w9000.c
> new file mode 100644
> index 0000000000000..7795508f93b29
> --- /dev/null
> +++ b/drivers/input/touchscreen/wacom_w9000.c
[ ... ]
> +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),
[Severity: High]
Is it safe to pass a stack-allocated variable (&command) as an I2C transfer
buffer?
If the underlying I2C adapter uses DMA, transferring from a stack address
can lead to kernel panics or silent memory corruption. This happens because
stack memory is often virtually mapped (when CONFIG_VMAP_STACK is enabled)
and is not guaranteed to be safely cacheline aligned.
Would it be better to allocate these buffers dynamically or embed a
DMA-safe buffer inside the wacom_w9000_data structure?
> + }, {
> + .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;
> + int error;
> + int retry = 0;
> + u8 data[CMD_QUERY_NUM_MAX];
[Severity: High]
Similarly, does passing this stack-allocated array down to wacom_w9000_read()
violate the DMA API requirements for the same reasons?
> +
> + for (; retry < CMD_QUERY_RETRIES; retry++) {
> + error = wacom_w9000_read(client, CMD_QUERY, wacom_data->variant->cmd_query_num,
> + data);
[ ... ]
> +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 error;
> + u8 data[MSG_COORD_NUM_MAX];
> + bool touch, rubber, side_button;
> + u16 x, y, pressure;
> + u8 distance = 0;
> +
> + error = i2c_master_recv(client, data, wacom_data->variant->msg_coord_num);
[Severity: High]
Can this call to i2c_master_recv() corrupt memory by DMAing into the
stack-allocated data array? Using a dedicated buffer allocated with kzalloc
or similar might prevent this issue on the coordinate data path.
> + if (error != wacom_data->variant->msg_coord_num) {
> + if (error >= 0)
> + error = -EIO;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260528074818.12151-1-hendrik-noack@gmx.de?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-28 9:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-28 7:48 [PATCH v8 0/2] Add support for Wacom W9000-series penabled touchscreens Hendrik Noack
2026-05-28 7:48 ` [PATCH v8 1/2] dt-bindings: Input: Add " Hendrik Noack
2026-05-28 8:32 ` sashiko-bot
2026-05-28 7:48 ` [PATCH v8 2/2] Input: Add support for " Hendrik Noack
2026-05-28 9:01 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox