* [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; 7+ 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] 7+ 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; 7+ 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] 7+ 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 2026-05-28 17:10 ` Conor Dooley 0 siblings, 1 reply; 7+ 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] 7+ messages in thread
* Re: [PATCH v8 1/2] dt-bindings: Input: Add Wacom W9000-series penabled touchscreens 2026-05-28 8:32 ` sashiko-bot @ 2026-05-28 17:10 ` Conor Dooley 0 siblings, 0 replies; 7+ messages in thread From: Conor Dooley @ 2026-05-28 17:10 UTC (permalink / raw) To: sashiko-reviews Cc: Hendrik Noack, robh, dmitry.torokhov, conor+dt, devicetree, linux-input [-- Attachment #1: Type: text/plain, Size: 2377 bytes --] On Thu, May 28, 2026 at 08:32:24AM +0000, sashiko-bot@kernel.org wrote: > 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? This doesn't matter, w9002 is as much of a "variant" as the others. > > > @@ -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? No, cos it is a gpios property. Just like how supplies don't have prefixes. > > [ ... ] > > > + #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? "digitiser" is generic enough for this not to matter IMO. > > > + compatible = "wacom,w9007a-lt03"; > > + reg = <0x56>; > > -- > Sashiko AI review · https://sashiko.dev/#/patchset/20260528074818.12151-1-hendrik-noack@gmx.de?part=1 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 7+ 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 2026-05-29 5:42 ` Dmitry Torokhov 1 sibling, 2 replies; 7+ 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] 7+ 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 2026-05-29 5:42 ` Dmitry Torokhov 1 sibling, 0 replies; 7+ 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] 7+ 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 @ 2026-05-29 5:42 ` Dmitry Torokhov 1 sibling, 0 replies; 7+ messages in thread From: Dmitry Torokhov @ 2026-05-29 5:42 UTC (permalink / raw) To: Hendrik Noack Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ferass El Hafidi, linux-input, devicetree, linux-kernel Hi Hendrik, On Thu, May 28, 2026 at 09:48:18AM +0200, Hendrik Noack wrote: > + > +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; We do not really need this flag as ling as you use input_device_enabled() in wacom_w9000_suspend(). ... > + > + 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); Here and in couple of other places we miss '\n' in the diagnostic messages. > + > + input_dev->name = wacom_data->variant->name; > + input_dev->id.bustype = BUS_I2C; > + input_dev->dev.parent = dev; This is not needed: devm_input_allocate_device() sets the patent for us. No need to resubmit, I made edits on my end. Thanks. -- Dmitry ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-29 5:42 UTC | newest] Thread overview: 7+ 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 17:10 ` Conor Dooley 2026-05-28 7:48 ` [PATCH v8 2/2] Input: Add support for " Hendrik Noack 2026-05-28 9:01 ` sashiko-bot 2026-05-29 5:42 ` Dmitry Torokhov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox