Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v1] Input: atlas - convert ACPI driver to a platform one
From: Rafael J. Wysocki @ 2026-03-14 11:54 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Linux ACPI, linux-input

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

In all cases in which a struct acpi_driver is used for binding a driver
to an ACPI device object, a corresponding platform device is created by
the ACPI core and that device is regarded as a proper representation of
underlying hardware.  Accordingly, a struct platform_driver should be
used by driver code to bind to that device.  There are multiple reasons
why drivers should not bind directly to ACPI device objects [1].

Overall, it is better to bind drivers to platform devices than to their
ACPI companions, so convert the ACPI Atlas button driver to a platform
one.

While this is not expected to alter functionality, it changes sysfs
layout and so it will be visible to user space.

Link: https://lore.kernel.org/all/2396510.ElGaqSPkdT@rafael.j.wysocki/ [1]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/input/misc/atlas_btns.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 5b9be2957746..47b31725e850 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -14,6 +14,7 @@
 #include <linux/input.h>
 #include <linux/types.h>
 #include <linux/acpi.h>
+#include <linux/platform_device.h>
 #include <linux/uaccess.h>
 
 #define ACPI_ATLAS_NAME		"Atlas ACPI"
@@ -57,8 +58,9 @@ static acpi_status acpi_atlas_button_handler(u32 function,
 	return status;
 }
 
-static int atlas_acpi_button_add(struct acpi_device *device)
+static int atlas_acpi_button_probe(struct platform_device *pdev)
 {
+	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
 	acpi_status status;
 	int i;
 	int err;
@@ -106,8 +108,9 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 	return err;
 }
 
-static void atlas_acpi_button_remove(struct acpi_device *device)
+static void atlas_acpi_button_remove(struct platform_device *pdev)
 {
+	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
 	acpi_status status;
 
 	status = acpi_remove_address_space_handler(device->handle,
@@ -124,16 +127,15 @@ static const struct acpi_device_id atlas_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 
-static struct acpi_driver atlas_acpi_driver = {
-	.name	= ACPI_ATLAS_NAME,
-	.class	= ACPI_ATLAS_CLASS,
-	.ids	= atlas_device_ids,
-	.ops	= {
-		.add	= atlas_acpi_button_add,
-		.remove	= atlas_acpi_button_remove,
+static struct platform_driver atlas_acpi_driver = {
+	.probe = atlas_acpi_button_probe,
+	.remove = atlas_acpi_button_remove,
+	.driver = {
+		.name = ACPI_ATLAS_NAME,
+		.acpi_match_table = atlas_device_ids,
 	},
 };
-module_acpi_driver(atlas_acpi_driver);
+module_platform_driver(atlas_acpi_driver);
 
 MODULE_AUTHOR("Jaya Kumar");
 MODULE_LICENSE("GPL");
-- 
2.51.0





^ permalink raw reply related

* Re: [PATCH 1/2] dt-bindings: input: touchscreen: edt-ft5x06: Add FocalTech FT3519
From: Krzysztof Kozlowski @ 2026-03-14 10:29 UTC (permalink / raw)
  To: Bhushan Shah
  Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-input, devicetree, linux-kernel
In-Reply-To: <20260313-edt-ft3519-v1-1-fe5ffc632fd2@machinesoul.in>

On Fri, Mar 13, 2026 at 12:09:50PM +0530, Bhushan Shah wrote:
> Document FocalTech FT3519 support by adding the compatible. It's 10
> point touchscreen, which works with same driver.
> 
> Signed-off-by: Bhushan Shah <bhushan.shah@machinesoul.in>
> ---
>  Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> index 6f90522de8c0..34161af90156 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
> @@ -40,6 +40,7 @@ properties:
>        - edt,edt-ft5506
>        - evervision,ev-ft5726
>        - focaltech,ft3518
> +      - focaltech,ft3519

Driver clearly indicates it is compatible with 3518 so express it with
fallback (see writing bindings, writing schema, example schema, DTS101
presentation slides).

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH 2/2] Input: edt-ft5x06 - add support for FocalTech FT3519
From: Krzysztof Kozlowski @ 2026-03-14 10:25 UTC (permalink / raw)
  To: Bhushan Shah
  Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-input, devicetree, linux-kernel
In-Reply-To: <20260313-edt-ft3519-v1-2-fe5ffc632fd2@machinesoul.in>

On Fri, Mar 13, 2026 at 12:09:51PM +0530, Bhushan Shah wrote:
> This driver is compatible with the FocalTech FT3519 touchscreen, which
> supports up to 10 concurrent touch points. Add a compatible for it.
> 
> Signed-off-by: Bhushan Shah <bhushan.shah@machinesoul.in>
> ---
>  drivers/input/touchscreen/edt-ft5x06.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
> index d0ab644be006..52188e1aa9bc 100644
> --- a/drivers/input/touchscreen/edt-ft5x06.c
> +++ b/drivers/input/touchscreen/edt-ft5x06.c
> @@ -1479,6 +1479,10 @@ static const struct edt_i2c_chip_data edt_ft3518_data = {
>  	.max_support_points = 10,
>  };
>  
> +static const struct edt_i2c_chip_data edt_ft3519_data = {
> +	.max_support_points = 10,
> +};

So same as edt_ft3518_data? Why are you duplicating it then?

Best regards,
Krzysztof


^ permalink raw reply

* [PATCH] xpad: Overhaul device data for wireless devices
From: Sanjay Govind @ 2026-03-14  7:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Vicki Pfau, Nilton Perim Neto, Mario Limonciello,
	Sanjay Govind, Pierre-Loup A. Griffais
  Cc: Antheas Kapenekakis, linux-input, linux-kernel

Xbox 360 wireless controllers expose information in the link and
capabilities reports.

Extract and use the vendor id for wireless controllers, and use
the subtype to build a nicer device name and product id.

Some xbox 360 controllers put a vid and pid into the stick capability
data, so check if this was done, and pull the vid, pid and revision from
there.

Signed-off-by: Sanjay Govind <sanjay.govind9@gmail.com>
---
 drivers/input/joystick/xpad.c | 138 +++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 3 deletions(-)

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index bf4accf3f581..2490eb21a534 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -94,6 +94,22 @@
 #define XTYPE_XBOXONE     3
 #define XTYPE_UNKNOWN     4
 
+#define FLAG_FORCE_FEEDBACK	0x01
+
+#define SUBTYPE_GAMEPAD			 0x01
+#define SUBTYPE_WHEEL			 0x02
+#define SUBTYPE_ARCADE_STICK	 0x03
+#define SUBTYPE_FLIGHT_SICK		 0x04
+#define SUBTYPE_DANCE_PAD		 0x05
+#define SUBTYPE_GUITAR			 0x06
+#define SUBTYPE_GUITAR_ALTERNATE 0x07
+#define SUBTYPE_DRUM_KIT		 0x08
+#define SUBTYPE_GUITAR_BASS		 0x0B
+#define SUBTYPE_RB_KEYBOARD		 0x0F
+#define SUBTYPE_ARCADE_PAD		 0x13
+#define SUBTYPE_TURNTABLE		 0x17
+#define SUBTYPE_PRO_GUITAR		 0x19
+
 /* Send power-off packet to xpad360w after holding the mode button for this many
  * seconds
  */
@@ -795,6 +811,9 @@ struct usb_xpad {
 	int xtype;			/* type of xbox device */
 	int packet_type;		/* type of the extended packet */
 	int pad_nr;			/* the order x360 pads were attached */
+	u8 sub_type;
+	u16 flags;
+	u16 wireless_vid;
 	const char *name;		/* name of the device */
 	struct work_struct work;	/* init/remove device from callback */
 	time64_t mode_btn_down_ts;
@@ -807,6 +826,8 @@ static void xpad_deinit_input(struct usb_xpad *xpad);
 static int xpad_start_input(struct usb_xpad *xpad);
 static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
 static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
+static int xpad_inquiry_pad_capabilities(struct usb_xpad *xpad);
+
 
 /*
  *	xpad_process_packet
@@ -1026,12 +1047,46 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
 	if (data[0] & 0x08) {
 		present = (data[1] & 0x80) != 0;
 
-		if (xpad->pad_present != present) {
+		/* delay prescence until after we get the link report */
+		if (!present && xpad->pad_present) {
 			xpad->pad_present = present;
 			schedule_work(&xpad->work);
 		}
 	}
 
+	/* Link report */
+	if (data[0] == 0x00 && data[1] == 0x0F) {
+		xpad->sub_type = data[25] & 0x7f;
+
+		/* Decode vendor id from link report */
+		xpad->wireless_vid = ((data[0x16] & 0xf) | data[0x18] << 4) << 8 | data[0x17];
+
+		if ((data[25] & 0x80) != 0)
+			xpad->flags |= FLAG_FORCE_FEEDBACK;
+
+		if (!xpad->pad_present) {
+			xpad->pad_present = true;
+			schedule_work(&xpad->work);
+		}
+		xpad_inquiry_pad_capabilities(xpad);
+	}
+
+	/* Capabilities report */
+	if (data[0] == 0x00 && data[1] == 0x05 && data[5] == 0x12) {
+		xpad->flags |= data[20];
+		/*
+		 * A bunch of vendors started putting vids and pids
+		 * into capabilities data because they can't be
+		 * retrieved by xinput easliy.
+		 * Not all of them do though, so check the vids match
+		 * before extracting that info.
+		 */
+		if (((data[11] << 8) | data[10]) == xpad->wireless_vid) {
+			xpad->dev->id.product = (data[13] << 8) | data[12];
+			xpad->dev->id.version = (data[15] << 8) | data[14];
+		}
+	}
+
 	/* Valid pad data */
 	if (data[1] != 0x1)
 		return;
@@ -1495,6 +1550,31 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
 	return xpad_try_sending_next_out_packet(xpad);
 }
 
+static int xpad_inquiry_pad_capabilities(struct usb_xpad *xpad)
+{
+	struct xpad_output_packet *packet =
+			&xpad->out_packets[XPAD_OUT_CMD_IDX];
+
+	guard(spinlock_irqsave)(&xpad->odata_lock);
+
+	packet->data[0] = 0x00;
+	packet->data[1] = 0x00;
+	packet->data[2] = 0x02;
+	packet->data[3] = 0x80;
+	packet->data[4] = 0x00;
+	packet->data[5] = 0x00;
+	packet->data[6] = 0x00;
+	packet->data[7] = 0x00;
+	packet->data[8] = 0x00;
+	packet->data[9] = 0x00;
+	packet->data[10] = 0x00;
+	packet->data[11] = 0x00;
+	packet->len = 12;
+	packet->pending = true;
+
+	return xpad_try_sending_next_out_packet(xpad);
+}
+
 static int xpad_start_xbox_one(struct usb_xpad *xpad)
 {
 	int error;
@@ -1965,8 +2045,60 @@ static int xpad_init_input(struct usb_xpad *xpad)
 	usb_to_input_id(xpad->udev, &input_dev->id);
 
 	if (xpad->xtype == XTYPE_XBOX360W) {
-		/* x360w controllers and the receiver have different ids */
-		input_dev->id.product = 0x02a1;
+		/*
+		 * x360w controllers on windows put the subtype into the product
+		 * for wheels and gamepads, but it makes sense to do it for all
+		 * subtypes
+		 */
+		input_dev->id.product = 0x02a0 + xpad->sub_type;
+		/* If the Link report has provided a vid, it won't be set to 1 */
+		if (xpad->wireless_vid != 1)
+			input_dev->id.vendor = xpad->wireless_vid;
+		switch (xpad->sub_type) {
+		case SUBTYPE_GAMEPAD:
+			input_dev->name = "Xbox 360 Wireless Controller";
+			break;
+		case SUBTYPE_WHEEL:
+			input_dev->name = "Xbox 360 Wireless Wheel";
+			break;
+		case SUBTYPE_ARCADE_STICK:
+			input_dev->name = "Xbox 360 Wireless Arcade Stick";
+			break;
+		case SUBTYPE_FLIGHT_SICK:
+			input_dev->name = "Xbox 360 Wireless Flight Stick";
+			break;
+		case SUBTYPE_DANCE_PAD:
+			input_dev->name = "Xbox 360 Wireless Dance Pad";
+			break;
+		case SUBTYPE_GUITAR:
+			input_dev->name = "Xbox 360 Wireless Guitar";
+			break;
+		case SUBTYPE_GUITAR_ALTERNATE:
+			input_dev->name = "Xbox 360 Wireless Alternate Guitar";
+			break;
+		case SUBTYPE_GUITAR_BASS:
+			input_dev->name = "Xbox 360 Wireless Bass Guitar";
+			break;
+		case SUBTYPE_DRUM_KIT:
+			/* Vendors used force feedback flag to differentiate these */
+			if (xpad->flags & FLAG_FORCE_FEEDBACK)
+				input_dev->name = "Xbox 360 Wireless Guitar Hero Drum Kit";
+			else
+				input_dev->name = "Xbox 360 Wireless Rock Band Drum Kit";
+			break;
+		case SUBTYPE_RB_KEYBOARD:
+			input_dev->name = "Xbox 360 Wireless Rock Band Keyboard";
+			break;
+		case SUBTYPE_ARCADE_PAD:
+			input_dev->name = "Xbox 360 Wireless Arcade Pad";
+			break;
+		case SUBTYPE_TURNTABLE:
+			input_dev->name = "Xbox 360 Wireless DJ Hero Turntable";
+			break;
+		case SUBTYPE_PRO_GUITAR:
+			input_dev->name = "Xbox 360 Wireless Rock Band Pro Guitar";
+			break;
+		}
 	}
 
 	input_dev->dev.parent = &xpad->intf->dev;
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 3/3] HID: input: Add support for multiple batteries per device
From: Lucas Zampieri @ 2026-03-14  1:05 UTC (permalink / raw)
  To: linux-input
  Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
	Sebastian Reichel, Bastien Nocera, linux-pm
In-Reply-To: <20260314010533.110278-1-lcasmz54@gmail.com>

Add support for HID devices that report multiple batteries, each
identified by its report ID.

The hid_device->battery pointer is replaced with a batteries list.
Batteries are named using the pattern hid-{uniq}-battery-{report_id}.
The hid_get_battery() helper returns the first battery in the list for
backwards compatibility with single-battery drivers.

Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
 drivers/hid/hid-core.c  |  4 ++++
 drivers/hid/hid-input.c | 44 ++++++++++++++++++++++++++++-------------
 include/linux/hid.h     | 11 ++++++++---
 3 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index da57cbf0a..58a31ee07 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2995,6 +2995,10 @@ struct hid_device *hid_allocate_device(void)
 	mutex_init(&hdev->ll_open_lock);
 	kref_init(&hdev->ref);
 
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+	INIT_LIST_HEAD(&hdev->batteries);
+#endif
+
 	ret = hid_bpf_device_init(hdev);
 	if (ret)
 		goto out_err;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index b5d34658b..8fff185fe 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -507,6 +507,18 @@ static int hidinput_get_battery_property(struct power_supply *psy,
 	return ret;
 }
 
+static struct hid_battery *hidinput_find_battery(struct hid_device *dev,
+						 int report_id)
+{
+	struct hid_battery *bat;
+
+	list_for_each_entry(bat, &dev->batteries, list) {
+		if (bat->report_id == report_id)
+			return bat;
+	}
+	return NULL;
+}
+
 static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 				  struct hid_field *field, bool is_percentage)
 {
@@ -517,13 +529,15 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	s32 min, max;
 	int error;
 
-	if (dev->battery)
-		return 0;	/* already initialized? */
+	/* Check if battery for this report ID already exists */
+	if (hidinput_find_battery(dev, field->report->id))
+		return 0;
 
 	quirks = find_battery_quirk(dev);
 
-	hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
-		dev->bus, dev->vendor, dev->product, dev->version, quirks);
+	hid_dbg(dev, "device %x:%x:%x %d quirks %d report_id %d\n",
+		dev->bus, dev->vendor, dev->product, dev->version, quirks,
+		field->report->id);
 
 	if (quirks & HID_BATTERY_QUIRK_IGNORE)
 		return 0;
@@ -538,9 +552,11 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 		goto err_free_bat;
 	}
 
-	psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
+	psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL,
+					"hid-%s-battery-%d",
 					strlen(dev->uniq) ?
-						dev->uniq : dev_name(&dev->dev));
+						dev->uniq : dev_name(&dev->dev),
+					field->report->id);
 	if (!psy_desc->name) {
 		error = -ENOMEM;
 		goto err_free_desc;
@@ -593,7 +609,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	}
 
 	power_supply_powers(bat->ps, &dev->dev);
-	dev->battery = bat;
+	list_add_tail(&bat->list, &dev->batteries);
 	return 0;
 
 err_free_name:
@@ -602,7 +618,6 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	devm_kfree(&dev->dev, psy_desc);
 err_free_bat:
 	devm_kfree(&dev->dev, bat);
-	dev->battery = NULL;
 	return error;
 }
 
@@ -620,12 +635,13 @@ static bool hidinput_update_battery_charge_status(struct hid_battery *bat,
 	return false;
 }
 
-static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
-				    int value)
+static void hidinput_update_battery(struct hid_device *dev, int report_id,
+				    unsigned int usage, int value)
 {
-	struct hid_battery *bat = dev->battery;
+	struct hid_battery *bat;
 	int capacity;
 
+	bat = hidinput_find_battery(dev, report_id);
 	if (!bat)
 		return;
 
@@ -661,8 +677,8 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	return 0;
 }
 
-static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
-				    int value)
+static void hidinput_update_battery(struct hid_device *dev, int report_id,
+				    unsigned int usage, int value)
 {
 }
 #endif	/* CONFIG_HID_BATTERY_STRENGTH */
@@ -1546,7 +1562,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
 		return;
 
 	if (usage->type == EV_PWR) {
-		hidinput_update_battery(hid, usage->hid, value);
+		hidinput_update_battery(hid, report->id, usage->hid, value);
 		return;
 	}
 
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 71beff003..442a80d79 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -648,6 +648,7 @@ enum hid_battery_status {
  * @avoid_query: if true, avoid querying battery (e.g., for stylus)
  * @present: if true, battery is present (may be dynamic)
  * @ratelimit_time: rate limiting for battery reports
+ * @list: list node for linking into hid_device's battery list
  */
 struct hid_battery {
 	struct hid_device *dev;
@@ -662,6 +663,7 @@ struct hid_battery {
 	bool avoid_query;
 	bool present;
 	ktime_t ratelimit_time;
+	struct list_head list;
 };
 
 struct hid_driver;
@@ -700,9 +702,10 @@ struct hid_device {
 #ifdef CONFIG_HID_BATTERY_STRENGTH
 	/*
 	 * Power supply information for HID devices which report
-	 * battery strength. battery is non-NULL if successfully registered.
+	 * battery strength. Each battery is tracked separately in the
+	 * batteries list.
 	 */
-	struct hid_battery *battery;
+	struct list_head batteries;
 #endif
 
 	unsigned long status;						/* see STAT flags above */
@@ -767,7 +770,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
 #ifdef CONFIG_HID_BATTERY_STRENGTH
 static inline struct hid_battery *hid_get_battery(struct hid_device *hdev)
 {
-	return hdev->battery;
+	if (list_empty(&hdev->batteries))
+		return NULL;
+	return list_first_entry(&hdev->batteries, struct hid_battery, list);
 }
 #endif
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 2/3] HID: input: Introduce struct hid_battery and refactor battery code
From: Lucas Zampieri @ 2026-03-14  1:05 UTC (permalink / raw)
  To: linux-input
  Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
	Sebastian Reichel, Bastien Nocera, linux-pm
In-Reply-To: <20260314010533.110278-1-lcasmz54@gmail.com>

Introduce struct hid_battery to encapsulate individual battery state,
preparing for future multi-battery support.

The new structure contains all battery-related fields previously stored
directly in hid_device (capacity, min, max, report_type, report_id,
charge_status, etc.). The hid_device->battery pointer type changes from
struct power_supply* to struct hid_battery*, and all battery functions
are refactored accordingly.

A hid_get_battery() helper is added for external drivers, with
hid-apple.c and hid-magicmouse.c updated to use the new API. The
hid-input-test.c KUnit tests are also updated for the new structure.

No functional changes for single-battery devices.

Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
 drivers/hid/hid-apple.c      |  10 +--
 drivers/hid/hid-input-test.c |  39 ++++++-----
 drivers/hid/hid-input.c      | 131 +++++++++++++++++++----------------
 drivers/hid/hid-magicmouse.c |  10 +--
 include/linux/hid.h          |  52 ++++++++++----
 5 files changed, 146 insertions(+), 96 deletions(-)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index fc5897a6b..8b8b05c8a 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -623,17 +623,19 @@ static int apple_fetch_battery(struct hid_device *hdev)
 	struct apple_sc *asc = hid_get_drvdata(hdev);
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
+	struct hid_battery *bat;
 
-	if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery)
+	bat = hid_get_battery(hdev);
+	if (!(asc->quirks & APPLE_RDESC_BATTERY) || !bat)
 		return -1;
 
-	report_enum = &hdev->report_enum[hdev->battery_report_type];
-	report = report_enum->report_id_hash[hdev->battery_report_id];
+	report_enum = &hdev->report_enum[bat->report_type];
+	report = report_enum->report_id_hash[bat->report_id];
 
 	if (!report || report->maxfield < 1)
 		return -1;
 
-	if (hdev->battery_capacity == hdev->battery_max)
+	if (bat->capacity == bat->max)
 		return -1;
 
 	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
index 6f5c71660..c92008daf 100644
--- a/drivers/hid/hid-input-test.c
+++ b/drivers/hid/hid-input-test.c
@@ -9,54 +9,59 @@
 
 static void hid_test_input_update_battery_charge_status(struct kunit *test)
 {
-	struct hid_device *dev;
+	struct hid_battery *bat;
 	bool handled;
 
-	dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
-	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+	bat = kunit_kzalloc(test, sizeof(*bat), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bat);
 
-	handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0);
+	handled = hidinput_update_battery_charge_status(bat, HID_DG_HEIGHT, 0);
 	KUNIT_EXPECT_FALSE(test, handled);
-	KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
+	KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
 
-	handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0);
+	handled = hidinput_update_battery_charge_status(bat, HID_BAT_CHARGING, 0);
 	KUNIT_EXPECT_TRUE(test, handled);
-	KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
+	KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
 
-	handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1);
+	handled = hidinput_update_battery_charge_status(bat, HID_BAT_CHARGING, 1);
 	KUNIT_EXPECT_TRUE(test, handled);
-	KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
+	KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_CHARGING);
 }
 
 static void hid_test_input_get_battery_property(struct kunit *test)
 {
 	struct power_supply *psy;
+	struct hid_battery *bat;
 	struct hid_device *dev;
 	union power_supply_propval val;
 	int ret;
 
 	dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
-	dev->battery_avoid_query = true;
+
+	bat = kunit_kzalloc(test, sizeof(*bat), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bat);
+	bat->dev = dev;
+	bat->avoid_query = true;
 
 	psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy);
-	psy->drv_data = dev;
+	psy->drv_data = bat;
 
-	dev->battery_status = HID_BATTERY_UNKNOWN;
-	dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+	bat->status = HID_BATTERY_UNKNOWN;
+	bat->charge_status = POWER_SUPPLY_STATUS_CHARGING;
 	ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
 	KUNIT_EXPECT_EQ(test, ret, 0);
 	KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN);
 
-	dev->battery_status = HID_BATTERY_REPORTED;
-	dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+	bat->status = HID_BATTERY_REPORTED;
+	bat->charge_status = POWER_SUPPLY_STATUS_CHARGING;
 	ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
 	KUNIT_EXPECT_EQ(test, ret, 0);
 	KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING);
 
-	dev->battery_status = HID_BATTERY_REPORTED;
-	dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+	bat->status = HID_BATTERY_REPORTED;
+	bat->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
 	ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
 	KUNIT_EXPECT_EQ(test, ret, 0);
 	KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING);
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7e0f971ef..b5d34658b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -416,18 +416,18 @@ static unsigned find_battery_quirk(struct hid_device *hdev)
 	return quirks;
 }
 
-static int hidinput_scale_battery_capacity(struct hid_device *dev,
+static int hidinput_scale_battery_capacity(struct hid_battery *bat,
 					   int value)
 {
-	if (dev->battery_min < dev->battery_max &&
-	    value >= dev->battery_min && value <= dev->battery_max)
-		value = ((value - dev->battery_min) * 100) /
-			(dev->battery_max - dev->battery_min);
+	if (bat->min < bat->max &&
+	    value >= bat->min && value <= bat->max)
+		value = ((value - bat->min) * 100) /
+			(bat->max - bat->min);
 
 	return value;
 }
 
-static int hidinput_query_battery_capacity(struct hid_device *dev)
+static int hidinput_query_battery_capacity(struct hid_battery *bat)
 {
 	int ret;
 
@@ -435,19 +435,20 @@ static int hidinput_query_battery_capacity(struct hid_device *dev)
 	if (!buf)
 		return -ENOMEM;
 
-	ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4,
-				 dev->battery_report_type, HID_REQ_GET_REPORT);
+	ret = hid_hw_raw_request(bat->dev, bat->report_id, buf, 4,
+				 bat->report_type, HID_REQ_GET_REPORT);
 	if (ret < 2)
 		return -ENODATA;
 
-	return hidinput_scale_battery_capacity(dev, buf[1]);
+	return hidinput_scale_battery_capacity(bat, buf[1]);
 }
 
 static int hidinput_get_battery_property(struct power_supply *psy,
 					 enum power_supply_property prop,
 					 union power_supply_propval *val)
 {
-	struct hid_device *dev = power_supply_get_drvdata(psy);
+	struct hid_battery *bat = power_supply_get_drvdata(psy);
+	struct hid_device *dev = bat->dev;
 	int value;
 	int ret = 0;
 
@@ -457,17 +458,17 @@ static int hidinput_get_battery_property(struct power_supply *psy,
 		break;
 
 	case POWER_SUPPLY_PROP_PRESENT:
-		val->intval = dev->battery_present;
+		val->intval = bat->present;
 		break;
 
 	case POWER_SUPPLY_PROP_CAPACITY:
-		if (dev->battery_status != HID_BATTERY_REPORTED &&
-		    !dev->battery_avoid_query) {
-			value = hidinput_query_battery_capacity(dev);
+		if (bat->status != HID_BATTERY_REPORTED &&
+		    !bat->avoid_query) {
+			value = hidinput_query_battery_capacity(bat);
 			if (value < 0)
 				return value;
 		} else  {
-			value = dev->battery_capacity;
+			value = bat->capacity;
 		}
 
 		val->intval = value;
@@ -478,20 +479,20 @@ static int hidinput_get_battery_property(struct power_supply *psy,
 		break;
 
 	case POWER_SUPPLY_PROP_STATUS:
-		if (dev->battery_status != HID_BATTERY_REPORTED &&
-		    !dev->battery_avoid_query) {
-			value = hidinput_query_battery_capacity(dev);
+		if (bat->status != HID_BATTERY_REPORTED &&
+		    !bat->avoid_query) {
+			value = hidinput_query_battery_capacity(bat);
 			if (value < 0)
 				return value;
 
-			dev->battery_capacity = value;
-			dev->battery_status = HID_BATTERY_QUERIED;
+			bat->capacity = value;
+			bat->status = HID_BATTERY_QUERIED;
 		}
 
-		if (dev->battery_status == HID_BATTERY_UNKNOWN)
+		if (bat->status == HID_BATTERY_UNKNOWN)
 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
 		else
-			val->intval = dev->battery_charge_status;
+			val->intval = bat->charge_status;
 		break;
 
 	case POWER_SUPPLY_PROP_SCOPE:
@@ -509,8 +510,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
 static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 				  struct hid_field *field, bool is_percentage)
 {
+	struct hid_battery *bat;
 	struct power_supply_desc *psy_desc;
-	struct power_supply_config psy_cfg = { .drv_data = dev, };
+	struct power_supply_config psy_cfg = { 0 };
 	unsigned quirks;
 	s32 min, max;
 	int error;
@@ -526,16 +528,22 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	if (quirks & HID_BATTERY_QUIRK_IGNORE)
 		return 0;
 
-	psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
-	if (!psy_desc)
+	bat = devm_kzalloc(&dev->dev, sizeof(*bat), GFP_KERNEL);
+	if (!bat)
 		return -ENOMEM;
 
+	psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
+	if (!psy_desc) {
+		error = -ENOMEM;
+		goto err_free_bat;
+	}
+
 	psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
 					strlen(dev->uniq) ?
 						dev->uniq : dev_name(&dev->dev));
 	if (!psy_desc->name) {
 		error = -ENOMEM;
-		goto err_free_mem;
+		goto err_free_desc;
 	}
 
 	psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
@@ -555,51 +563,57 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	if (quirks & HID_BATTERY_QUIRK_FEATURE)
 		report_type = HID_FEATURE_REPORT;
 
-	dev->battery_min = min;
-	dev->battery_max = max;
-	dev->battery_report_type = report_type;
-	dev->battery_report_id = field->report->id;
-	dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+	bat->dev = dev;
+	bat->min = min;
+	bat->max = max;
+	bat->report_type = report_type;
+	bat->report_id = field->report->id;
+	bat->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+	bat->status = HID_BATTERY_UNKNOWN;
 
 	/*
 	 * Stylus is normally not connected to the device and thus we
 	 * can't query the device and get meaningful battery strength.
 	 * We have to wait for the device to report it on its own.
 	 */
-	dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
-				   field->physical == HID_DG_STYLUS;
+	bat->avoid_query = report_type == HID_INPUT_REPORT &&
+			   field->physical == HID_DG_STYLUS;
 
 	if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
-		dev->battery_avoid_query = true;
+		bat->avoid_query = true;
 
-	dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
+	bat->present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
 
-	dev->battery = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
-	if (IS_ERR(dev->battery)) {
-		error = PTR_ERR(dev->battery);
+	psy_cfg.drv_data = bat;
+	bat->ps = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
+	if (IS_ERR(bat->ps)) {
+		error = PTR_ERR(bat->ps);
 		hid_warn(dev, "can't register power supply: %d\n", error);
 		goto err_free_name;
 	}
 
-	power_supply_powers(dev->battery, &dev->dev);
+	power_supply_powers(bat->ps, &dev->dev);
+	dev->battery = bat;
 	return 0;
 
 err_free_name:
 	devm_kfree(&dev->dev, psy_desc->name);
-err_free_mem:
+err_free_desc:
 	devm_kfree(&dev->dev, psy_desc);
+err_free_bat:
+	devm_kfree(&dev->dev, bat);
 	dev->battery = NULL;
 	return error;
 }
 
-static bool hidinput_update_battery_charge_status(struct hid_device *dev,
+static bool hidinput_update_battery_charge_status(struct hid_battery *bat,
 						  unsigned int usage, int value)
 {
 	switch (usage) {
 	case HID_BAT_CHARGING:
-		dev->battery_charge_status = value ?
-					     POWER_SUPPLY_STATUS_CHARGING :
-					     POWER_SUPPLY_STATUS_DISCHARGING;
+		bat->charge_status = value ?
+				     POWER_SUPPLY_STATUS_CHARGING :
+				     POWER_SUPPLY_STATUS_DISCHARGING;
 		return true;
 	}
 
@@ -609,34 +623,35 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
 static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
 				    int value)
 {
+	struct hid_battery *bat = dev->battery;
 	int capacity;
 
-	if (!dev->battery)
+	if (!bat)
 		return;
 
-	if (hidinput_update_battery_charge_status(dev, usage, value)) {
-		dev->battery_present = true;
-		power_supply_changed(dev->battery);
+	if (hidinput_update_battery_charge_status(bat, usage, value)) {
+		bat->present = true;
+		power_supply_changed(bat->ps);
 		return;
 	}
 
 	if ((usage & HID_USAGE_PAGE) == HID_UP_DIGITIZER && value == 0)
 		return;
 
-	if (value < dev->battery_min || value > dev->battery_max)
+	if (value < bat->min || value > bat->max)
 		return;
 
-	capacity = hidinput_scale_battery_capacity(dev, value);
+	capacity = hidinput_scale_battery_capacity(bat, value);
 
-	if (dev->battery_status != HID_BATTERY_REPORTED ||
-	    capacity != dev->battery_capacity ||
-	    ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
-		dev->battery_present = true;
-		dev->battery_capacity = capacity;
-		dev->battery_status = HID_BATTERY_REPORTED;
-		dev->battery_ratelimit_time =
+	if (bat->status != HID_BATTERY_REPORTED ||
+	    capacity != bat->capacity ||
+	    ktime_after(ktime_get_coarse(), bat->ratelimit_time)) {
+		bat->present = true;
+		bat->capacity = capacity;
+		bat->status = HID_BATTERY_REPORTED;
+		bat->ratelimit_time =
 			ktime_add_ms(ktime_get_coarse(), 30 * 1000);
-		power_supply_changed(dev->battery);
+		power_supply_changed(bat->ps);
 	}
 }
 #else  /* !CONFIG_HID_BATTERY_STRENGTH */
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 9eadf3252..e70bd3dc0 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -817,19 +817,21 @@ static int magicmouse_fetch_battery(struct hid_device *hdev)
 #ifdef CONFIG_HID_BATTERY_STRENGTH
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
+	struct hid_battery *bat;
 
-	if (!hdev->battery ||
+	bat = hid_get_battery(hdev);
+	if (!bat ||
 	    (!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
 	     !is_usb_magictrackpad2(hdev->vendor, hdev->product)))
 		return -1;
 
-	report_enum = &hdev->report_enum[hdev->battery_report_type];
-	report = report_enum->report_id_hash[hdev->battery_report_id];
+	report_enum = &hdev->report_enum[bat->report_type];
+	report = report_enum->report_id_hash[bat->report_id];
 
 	if (!report || report->maxfield < 1)
 		return -1;
 
-	if (hdev->battery_capacity == hdev->battery_max)
+	if (bat->capacity == bat->max)
 		return -1;
 
 	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 44357295b..71beff003 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -634,6 +634,36 @@ enum hid_battery_status {
 	HID_BATTERY_REPORTED,		/* Device sent unsolicited battery strength report */
 };
 
+/**
+ * struct hid_battery - represents a single battery power supply
+ * @dev: pointer to the parent hid_device
+ * @ps: the power supply instance
+ * @min: minimum battery value from HID descriptor
+ * @max: maximum battery value from HID descriptor
+ * @report_type: HID report type (input/feature)
+ * @report_id: HID report ID for this battery
+ * @charge_status: current charging status
+ * @status: battery reporting status
+ * @capacity: current battery capacity (0-100)
+ * @avoid_query: if true, avoid querying battery (e.g., for stylus)
+ * @present: if true, battery is present (may be dynamic)
+ * @ratelimit_time: rate limiting for battery reports
+ */
+struct hid_battery {
+	struct hid_device *dev;
+	struct power_supply *ps;
+	__s32 min;
+	__s32 max;
+	__s32 report_type;
+	__s32 report_id;
+	__s32 charge_status;
+	enum hid_battery_status status;
+	__s32 capacity;
+	bool avoid_query;
+	bool present;
+	ktime_t ratelimit_time;
+};
+
 struct hid_driver;
 struct hid_ll_driver;
 
@@ -670,20 +700,9 @@ struct hid_device {
 #ifdef CONFIG_HID_BATTERY_STRENGTH
 	/*
 	 * Power supply information for HID devices which report
-	 * battery strength. power_supply was successfully registered if
-	 * battery is non-NULL.
+	 * battery strength. battery is non-NULL if successfully registered.
 	 */
-	struct power_supply *battery;
-	__s32 battery_capacity;
-	__s32 battery_min;
-	__s32 battery_max;
-	__s32 battery_report_type;
-	__s32 battery_report_id;
-	__s32 battery_charge_status;
-	enum hid_battery_status battery_status;
-	bool battery_avoid_query;
-	bool battery_present;
-	ktime_t battery_ratelimit_time;
+	struct hid_battery *battery;
 #endif
 
 	unsigned long status;						/* see STAT flags above */
@@ -745,6 +764,13 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+static inline struct hid_battery *hid_get_battery(struct hid_device *hdev)
+{
+	return hdev->battery;
+}
+#endif
+
 #define HID_GLOBAL_STACK_SIZE 4
 #define HID_COLLECTION_STACK_SIZE 4
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 1/3] HID: input: Convert battery code to devm_*
From: Lucas Zampieri @ 2026-03-14  1:05 UTC (permalink / raw)
  To: linux-input
  Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
	Sebastian Reichel, Bastien Nocera, linux-pm
In-Reply-To: <20260314010533.110278-1-lcasmz54@gmail.com>

Convert the HID battery code to use devm_* managed resource APIs for
the power_supply_desc allocation, battery name string, and power supply
registration.

The error path uses devm_kfree() to clean up allocated memory if
devm_power_supply_register() fails, preventing memory waste on repeated
setup attempts. The hidinput_cleanup_battery() function is removed as
devm handles cleanup automatically.

Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
 drivers/hid/hid-input.c | 34 +++++++---------------------------
 1 file changed, 7 insertions(+), 27 deletions(-)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 395138372..7e0f971ef 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -526,13 +526,13 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	if (quirks & HID_BATTERY_QUIRK_IGNORE)
 		return 0;
 
-	psy_desc = kzalloc_obj(*psy_desc);
+	psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
 	if (!psy_desc)
 		return -ENOMEM;
 
-	psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery",
-				   strlen(dev->uniq) ?
-					dev->uniq : dev_name(&dev->dev));
+	psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
+					strlen(dev->uniq) ?
+						dev->uniq : dev_name(&dev->dev));
 	if (!psy_desc->name) {
 		error = -ENOMEM;
 		goto err_free_mem;
@@ -574,7 +574,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 
 	dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
 
-	dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
+	dev->battery = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
 	if (IS_ERR(dev->battery)) {
 		error = PTR_ERR(dev->battery);
 		hid_warn(dev, "can't register power supply: %d\n", error);
@@ -585,27 +585,13 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	return 0;
 
 err_free_name:
-	kfree(psy_desc->name);
+	devm_kfree(&dev->dev, psy_desc->name);
 err_free_mem:
-	kfree(psy_desc);
+	devm_kfree(&dev->dev, psy_desc);
 	dev->battery = NULL;
 	return error;
 }
 
-static void hidinput_cleanup_battery(struct hid_device *dev)
-{
-	const struct power_supply_desc *psy_desc;
-
-	if (!dev->battery)
-		return;
-
-	psy_desc = dev->battery->desc;
-	power_supply_unregister(dev->battery);
-	kfree(psy_desc->name);
-	kfree(psy_desc);
-	dev->battery = NULL;
-}
-
 static bool hidinput_update_battery_charge_status(struct hid_device *dev,
 						  unsigned int usage, int value)
 {
@@ -660,10 +646,6 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	return 0;
 }
 
-static void hidinput_cleanup_battery(struct hid_device *dev)
-{
-}
-
 static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
 				    int value)
 {
@@ -2393,8 +2375,6 @@ void hidinput_disconnect(struct hid_device *hid)
 {
 	struct hid_input *hidinput, *next;
 
-	hidinput_cleanup_battery(hid);
-
 	list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
 		list_del(&hidinput->list);
 		if (hidinput->registered)
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 0/3] HID: Add support for multiple batteries per device
From: Lucas Zampieri @ 2026-03-14  1:05 UTC (permalink / raw)
  To: linux-input
  Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
	Sebastian Reichel, Bastien Nocera, linux-pm

This series adds support for HID devices with multiple batteries.

Currently, the HID battery reporting subsystem only supports one battery per
device. There are several devices with multiple batteries that would benefit
from this support:
- Gaming headsets with batteries in both the headset and charging dock
- Wireless earbuds with per-earbud batteries plus charging case
- Split keyboards with per-side batteries

## Proposed Solution

This series introduces struct hid_battery to encapsulate individual battery
state, replaces the old battery fields with a list-based approach, and adds
support for multiple batteries tracked within struct hid_device. Batteries
are identified by report ID and named as hid-{uniq}-battery-{id}. The
implementation is fully backwards compatible with single-battery devices
through a helper function. The series first converts the battery code to
devm_* as preparatory cleanup, which simplifies the subsequent refactoring
and reduces risk of memory management bugs.

## Testing

Tested with split keyboard hardware (Dactyl 5x6) using custom ZMK firmware
that implements per-side HID battery reporting. Each battery (left and right
keyboard halves) reports independently through the power supply interface with
distinct report IDs (0x05 and 0x06).

Test firmware available on my personal fork at:
https://github.com/zampierilucas/zmk/tree/feat/individual-hid-battery-reporting
If this series gets merged, these changes will be proposed to upstream ZMK.

HID descriptor and recording captured with hid-recorder:

D: 0
R: 162 05 01 09 06 a1 01 85 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 75 08 95 01 81 03 05 07 15 00 25 01 19 00 29 67 75 01 95 68 81 02 c0 05 0c 09 01 a1 01 85 02 05 0c 15 00 26 ff 0f 19 00 2a ff 0f 75 10 95 06 81 00 c0 05 84 09 05 a1 01 05 85 85 05 09 44 15 00 25 01 35 00 45 01 75 08 95 01 81 02 09 65 15 00 25 64 35 00 45 64 75 08 95 01 81 02 c0 05 84 09 05 a1 01 05 85 85 06 09 44 15 00 25 01 35 00 45 01 75 08 95 01 81 02 09 65 15 00 25 64 35 00 45 64 75 08 95 01 81 02 c0
N: ZMK Project Dactyl 5x6
P: usb-0000:2d:00.3-4.2/input2
I: 3 1d50 615e
D: 0
E: 0.000000 3 05 00 56
E: 0.000977 3 05 00 56
E: 1.490974 3 06 00 52
E: 1.491958 3 06 00 52
E: 6.492979 3 06 00 53
E: 6.493962 3 06 00 53

The recording shows both batteries reporting with different charge levels
(Report ID 05: 86%, Report ID 06: 82%-83%), demonstrating the multi-battery
functionality. This can be used to verify UPower compatibility.

## Future Work: Userspace Integration

As suggested by Bastien, semantic battery differentiation (e.g., "left
earbud" vs "right earbud") requires userspace coordination, as HID
reports typically lack role metadata.

This will require:
1. systemd/hwdb entries for device-specific battery role mappings
2. UPower updates to enumerate and group multi-battery devices
3. Desktop environment changes to display batteries with meaningful labels

This kernel infrastructure is a prerequisite for that userspace work.

Lucas Zampieri (3):
  HID: input: Convert battery code to devm_*
  HID: input: Introduce struct hid_battery and refactor battery code
  HID: input: Add support for multiple batteries per device

Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>

Changes in v7:
- Rebased on top of hid.git for-next branch as requested by Jiri
- Adapted to new battery_present field and HID_BATTERY_QUIRK_DYNAMIC
  quirk introduced upstream
- Adapted to kzalloc_obj() -> devm_kzalloc() and __free(kfree) cleanup
  guard changes in upstream

Changes in v6:
- Split v5 patch 2/2 into two separate patches as suggested by Benjamin:
  - Patch 2/3: Introduce struct hid_battery and convert existing code
    (no functional change for single-battery devices)
  - Patch 3/3: Add multi-battery list support
- Renamed hid_get_first_battery() to hid_get_battery() as suggested by
  Benjamin
- Added devm_kfree() calls in error path of hidinput_setup_battery() for
  proper cleanup if devm_power_supply_register() fails

Changes in v5:
- Split the monolithic v4 patch into two logical patches as suggested by
  Benjamin, devm_* conversion, then struct refactor and multi-battery support
  combined

Changes in v4:
- Added missing hidinput_update_battery() stub in #else block for
  CONFIG_HID_BATTERY_STRENGTH=n builds
- Reported-by: kernel test robot <lkp@intel.com>
- Closes: https://lore.kernel.org/oe-kbuild-all/202511201624.yUv4VtBv-lkp@intel.com/

Changes in v3:
- Squashed the three v2 patches into a single patch as suggested by
  Benjamin
- Removed all legacy dev->battery_* fields, using list-based storage only
- Changed battery naming to include report ID: hid-{uniq}-battery-{report_id}
- Converted battery memory management to devm_* for automatic cleanup
- Updated hidinput_update_battery() to take struct hid_battery directly
- Added hid_get_first_battery() helper for external driver compatibility
- Updated hid-apple.c and hid-magicmouse.c to use new battery API
- Simplified cover letter based on feedback

Changes in v2:
- Split the monolithic v1 patch into three logical patches for easier review:
  1. Introduce struct hid_battery (pure structure addition)
  2. Refactor existing code to use the new structure (internal changes)
  3. Add multi-battery support (new functionality)
- Added detailed testing section with hardware specifics
- Added hid-recorder output (dactyl-hid-recording.txt) demonstrating two-battery
  HID descriptor for UPower validation
- Added "Future Work: Userspace Integration" section addressing Bastien's feedback
  about semantic battery differentiation
- Added hardware examples with product links to commit messages (per Bastien's
  suggestion)
- No functional changes from v1, only improved patch organization and documentation

 drivers/hid/hid-apple.c      |  10 +-
 drivers/hid/hid-core.c       |   4 +
 drivers/hid/hid-input-test.c |  39 ++++---
 drivers/hid/hid-input.c      | 197 ++++++++++++++++++-----------------
 drivers/hid/hid-magicmouse.c |  10 +-
 include/linux/hid.h          |  57 +++++++---
 6 files changed, 186 insertions(+), 131 deletions(-)


base-commit: 73965d0aefc8ef6504552e5805f645d58a8727b0
--
2.53.0


^ permalink raw reply

* Re: [PATCH 01/15] tracepoint: Add trace_invoke_##name() API
From: Keith Busch @ 2026-03-14  0:24 UTC (permalink / raw)
  To: Vineeth Remanan Pillai
  Cc: Peter Zijlstra, Steven Rostedt, Dmitry Ilvokhin, Masami Hiramatsu,
	Mathieu Desnoyers, Ingo Molnar, Jens Axboe, io-uring,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexei Starovoitov, Daniel Borkmann, Marcelo Ricardo Leitner,
	Xin Long, Jon Maloy, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	netdev, bpf, linux-sctp, tipc-discussion, dev, Oded Gabbay,
	Koby Elbaz, dri-devel, Rafael J. Wysocki, Viresh Kumar,
	Gautham R. Shenoy, Huang Rui, Mario Limonciello, Len Brown,
	Srinivas Pandruvada, linux-pm, MyungJoo Ham, Kyungmin Park,
	Chanwoo Choi, Christian König, Sumit Semwal, linaro-mm-sig,
	Eddie James, Andrew Jeffery, Joel Stanley, linux-fsi,
	David Airlie, Simona Vetter, Alex Deucher, Danilo Krummrich,
	Matthew Brost, Philipp Stanner, Harry Wentland, Leo Li, amd-gfx,
	Jiri Kosina, Benjamin Tissoires, linux-input, Wolfram Sang,
	linux-i2c, Mark Brown, Michael Hennerich, Nuno Sá, linux-spi,
	James E.J. Bottomley, Martin K. Petersen, linux-scsi, Chris Mason,
	David Sterba, linux-btrfs, linux-trace-kernel, linux-kernel
In-Reply-To: <CAO7JXPiu8-LE_gG001_GQLoGVYakPdzmH2SXLqfzJjEUxbn1Rw@mail.gmail.com>

On Thu, Mar 12, 2026 at 12:05:37PM -0400, Vineeth Remanan Pillai wrote:
> On Thu, Mar 12, 2026 at 11:53 AM Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > That seems like an unreasonable waste of energy. You could've had claude
> > write a Coccinelle script for you and saved a ton of tokens.
> 
> Yeah true, Steve also mentioned this to me offline. Haven't used
> Coccinelle before, but now I know :-)

[+ Chris Mason]

At the risk of creating a distraction...

This discussion got me thinking the right skill loaded should have the
AI implicitly use coccinelle to generate the patchset rather than do it
by hand. You could prompt with simple language for a pattern
substitution rather than explicitly request coccinelle, and it should
generate a patch set using a script rather than spending tokens on doing
it "by hand".

I sent such a "skill" to Chris' kernel "review-prompts":

  https://github.com/masoncl/review-prompts/pull/35

I used patch one from this series as the starting point and let the AI
figure the rest out. The result actually found additional patterns that
could take advantage of the optimisation that this series did not
include. The resulting kernel tree that the above github pull request
references cost 2.8k tokens to create with the skill.

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: input: touchscreen: ti,tsc2005: Add wakeup-source
From: Rob Herring @ 2026-03-13 23:23 UTC (permalink / raw)
  To: phucduc.bui
  Cc: Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley, Ingo Molnar,
	Thomas Gleixner, Marek Vasut, Michael Welling, linux-input,
	devicetree, linux-kernel
In-Reply-To: <20260309110045.108209-2-phucduc.bui@gmail.com>

On Mon, Mar 09, 2026 at 06:00:43PM +0700, phucduc.bui@gmail.com wrote:
> From: bui duc phuc <phucduc.bui@gmail.com>
> 
> The tsc200x driver uses the "wakeup-source" device tree property to
> determine whether the device should be configured as a system wakeup
> source.
> 
> In the driver, this property is read with:
> 
>     device_init_wakeup(dev,
>                        device_property_read_bool(dev, "wakeup-source"));

Write your commit messages independent of the Linux driver.

> 
> Document this property in the binding to make it visible to DT schema
> validation tools and to clarify its usage in device tree descriptions.
> 
> Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
> ---
>  .../devicetree/bindings/input/touchscreen/ti,tsc2005.yaml  | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> index 7187c390b2f5..c0aae044d7d4 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> @@ -55,6 +55,9 @@ properties:
>    touchscreen-size-x: true
>    touchscreen-size-y: true
>  
> +  wakeup-source:
> +    type: boolean
> +
>  allOf:
>    - $ref: touchscreen.yaml#
>    - if:
> @@ -97,6 +100,8 @@ examples:
>  
>              ti,x-plate-ohms = <280>;
>              ti,esd-recovery-timeout-ms = <8000>;
> +
> +            wakeup-source;
>          };
>      };
>    - |
> @@ -124,5 +129,7 @@ examples:
>  
>              ti,x-plate-ohms = <280>;
>              ti,esd-recovery-timeout-ms = <8000>;
> +
> +            wakeup-source;
>          };
>      };
> -- 
> 2.43.0
> 

^ permalink raw reply

* Re: [PATCH v6 4/4] Input: Add TouchNetix aXiom I2C Touchscreen support
From: Marco Felsch @ 2026-03-13 19:50 UTC (permalink / raw)
  To: Andrew Thomas
  Cc: Luis Chamberlain, Russ Weight, Greg Kroah-Hartman,
	Rafael J. Wysocki, Andrew Morton, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Kamel Bouhara,
	Marco Felsch, Henrik Rydberg, Danilo Krummrich, linux-kernel,
	devicetree, linux-input
In-Reply-To: <rnbwxsdiwjojk7354c6k4us6xxl3qpbyt2lrbhgqz77avrdwga@tqb6voucuysi>

Hi Andrew,

thanks for your feedback! Please see below.

On 26-03-13, Andrew Thomas wrote:
> On Tue, Mar 03, 2026 at 11:41:22PM +0100, Marco Felsch wrote:
> >This adds the initial support for the TouchNetix AX54A touchcontroller
> >which is part of TouchNetix's aXiom touchscreen controller family.
> >
> >The TouchNetix aXiom family provides two physical interfaces: SPI and
> >I2C. This patch covers only the I2C interface.
> >
> >Apart the input event handling the driver supports firmware updates too.
> >One firmware interface handles the touchcontroller firmware (AXFW)
> >update the other handles the touchcontroller configuration (TH2CFGBIN)
> >update.
> >
> >Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> >---

...

> >+static int axiom_u02_enter_bootloader(struct axiom_data *ts)
> >+{
> >+	struct axiom_u02_rev1_system_manager_msg msg = { };
> >+	struct device *dev = ts->dev;
> >+	unsigned int val;
> >+	int error;
> >+
> >+	if (!axiom_driver_supports_usage(ts, AXIOM_U02))
> >+		return -EINVAL;
> >+
> >+	/*
> >+	 * Enter the bootloader mode requires 3 consecutive messages so we can't
> >+	 * check for the response.
> >+	 * TODO: Check if it's required to add a delay between the consecutive
> >+	 * CMD_ENTERBOOTLOADER cmds.
> >+	 */
> >+	msg.command = cpu_to_le16(AXIOM_U02_REV1_CMD_ENTERBOOTLOADER);
> >+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY1);
> >+	error = axiom_u02_send_msg(ts, &msg, false);
> 
> As mentioned before the delay between commands is too short and the
> next command is sent before u02 is ready, which means the driver fails
> to put axiom into the bootloader.

Please see my comment [1].

> Have you tested with an i2c speed of 400KHz?

Yes, my target platform is based on a i.MX8MP.

> All you need is to put true in above to wait for the bootloader command.
> error = axiom_u02_send_msg(ts, &msg, true);

Please see my comment [1].

> Just dont do it for the last command.

Please see my comment [1].

> I am not too sure why you are having issues with this, this is how we
> do it for all our devices.

Please see my comment [1].

On what platform do you perform the tests?

> >+	if (error) {
> >+		dev_err(dev, "Failed to send bootloader-key1: %d\n", error);
> >+		return error;
> >+	}
> >+
> >+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY2);
> >+	error = axiom_u02_send_msg(ts, &msg, false);
> 
> Here also.

Please see my comment [1].

> >+	if (error) {
> >+		dev_err(dev, "Failed to send bootloader-key2: %d\n", error);
> >+		return error;
> >+	}
> >+
> >+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY3);
> >+	error = axiom_u02_send_msg(ts, &msg, false);
> >+	if (error) {
> >+		dev_err(dev, "Failed to send bootloader-key3: %d\n", error);
> >+		return error;
> >+	}
> >+
> >+	/* Sleep before the first read to give the device time */
> >+	fsleep(250 * USEC_PER_MSEC);
> >+
> >+	/* Wait till the device reports it is in bootloader mode */
> >+	error = regmap_read_poll_timeout(ts->regmap,
> >+					 AXIOM_U31_REV1_DEVICE_ID_HIGH_REG, val,
> >+					 FIELD_GET(AXIOM_U31_REV1_MODE_MASK, val) ==
> >+						AXIOM_U31_REV1_MODE_BLP,
> >+					 250 * USEC_PER_MSEC, USEC_PER_SEC);
> >+	if (error)
> >+		return error;
> >+
> >+	return 0;
> >+}
> >+
> 
> ...
> 
> 
> Other than the above comments I have no issues with the driver.

If you're fine with the patch you could add your acked-by [2] :)

> We can support more usages in a later patch.

Sure :)

[1] https://lore.kernel.org/all/4x3dnedfzf3rqzsy3wjdoj6yaxmy6kop37xhxeao4vjer7ifdi@35ux42ztq3eb/
[2] https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by

Regards,
  Marco
-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |

^ permalink raw reply

* [PATCH v2] dt-bindings: touchscreen: trivial-touch: Move allOf: after required:
From: Marek Vasut @ 2026-03-13 19:33 UTC (permalink / raw)
  To: devicetree
  Cc: Marek Vasut, Conor Dooley, Frank Li, Conor Dooley,
	Dmitry Torokhov, Job Noorman, Krzysztof Kozlowski, Rob Herring,
	linux-input, linux-renesas-soc

Majority of schemas place 'allOf:' after 'required:' . Documentation
"Documentation/devicetree/bindings/writing-schema.rst" also hints at
this ordering. Trivially update this schema. No functional change.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
NOTE: This comes from https://lore.kernel.org/all/20260117-grinning-heavy-crab-11f245@quoll/
      where krzk comments "allOf: should be placed after required: block."
---
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Frank Li <Frank.Li@nxp.com>
Cc: Job Noorman <job@noorman.info>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-input@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: - Fix up the nits from Frank
    - Add RB from Frank
    - Add AB from Conor
---
 .../bindings/input/touchscreen/trivial-touch.yaml           | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
index 6441d21223caf..6316a8d32f39b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
@@ -53,14 +53,14 @@ properties:
 
   wakeup-source: true
 
-allOf:
-  - $ref: touchscreen.yaml
-
 required:
   - compatible
   - reg
   - interrupts
 
+allOf:
+  - $ref: touchscreen.yaml
+
 unevaluatedProperties: false
 
 examples:
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH 02/61] btrfs: Prefer IS_ERR_OR_NULL over manual NULL check
From: David Sterba @ 2026-03-13 19:22 UTC (permalink / raw)
  To: Philipp Hahn
  Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
	gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
	linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
	linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
	linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
	linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
	linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
	linux-sctp, linux-security-module, linux-sh, linux-sound,
	linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
	netdev, ntfs3, samba-technical, sched-ext, target-devel,
	tipc-discussion, v9fs, Chris Mason, David Sterba
In-Reply-To: <20260310-b4-is_err_or_null-v1-2-bd63b656022d@avm.de>

On Tue, Mar 10, 2026 at 12:48:28PM +0100, Philipp Hahn wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
> 
> IS_ERR_OR_NULL() already uses likely(!ptr) internally. checkpatch does
> not like nesting it:
> > WARNING: nested (un)?likely() calls, IS_ERR_OR_NULL already uses
> > unlikely() internally
> Remove the explicit use of likely().
> 
> Change generated with coccinelle.
> 
> To: Chris Mason <clm@fb.com>
> To: David Sterba <dsterba@suse.com>
> Cc: linux-btrfs@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>

Added to for-next, we seem to be using IS_ERR_OR_NULL() already in a
few other places so this is makes sense for consistency. Thanks.

^ permalink raw reply

* Re: [PATCH 4/4] HID: core: Export device version via HID_FIRMWARE_VERSION uevent
From: Daniel Schaefer @ 2026-03-13 18:20 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: linux-input, Richard Hughes, Jiri Kosina, Benjamin Tissoires,
	linux
In-Reply-To: <6b53a537-9989-4b34-b033-402773c871be@amd.com>

>  Isn't this in
> hid.git#for-7.1/lenovo-v2

Oh yes okay, I with this already in place, I should make my patches
set hdev->firmware_version instead of hdev->version.
Will send another series and drop my last patch in favor of yours:
https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git/commit/?h=for-7.1/lenovo-v2&id=6ca9029c823b7853e980585e757343e0e84227cd


On Sat, Mar 14, 2026 at 2:00 AM Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
>
>
> On 3/13/2026 12:56 PM, Daniel Schaefer wrote:
> > Expose the HID device version to userspace via the new
> > HID_FIRMWARE_VERSION uevent property. This enables userspace tools
> > (such as fwupd and hidapi) to retrieve device firmware version
> > information, providing parity with Windows HidD_GetAttributes() API
> > which returns VID, PID, and VersionNumber.
> >
> > The version is exported as a 4-digit uppercase hexadecimal value
> > (e.g., "0100" for version 1.0), consistent with how USB devices
> > report bcdDevice.
> >
> > fwupd can handle this since:
> > https://github.com/fwupd/fwupd/commit/fb0d4cc98abe253003ea0e1837277fd42971e0de
> > But the kernel hasn't yet exposed this.
> >
> > hidapi patch is in-flight: https://github.com/libusb/hidapi/pull/777
> >
> > Cc: Richard Hughes <richard@hughsie.com>
> > Cc: Mario Limonciello <mario.limonciello@amd.com>
> > Cc: Jiri Kosina <jikos@kernel.org>
> > Cc: Benjamin Tissoires <bentiss@kernel.org>
> > Cc: linux@frame.work
> > Signed-off-by: Daniel Schaefer <dhs@frame.work>
> > ---
> >   drivers/hid/hid-core.c | 3 +++
> >   1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> > index da57cbf0af26..c2075d5b40c3 100644
> > --- a/drivers/hid/hid-core.c
> > +++ b/drivers/hid/hid-core.c
> > @@ -2884,6 +2884,9 @@ static int hid_uevent(const struct device *dev, struct kobj_uevent_env *env)
> >       if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
> >               return -ENOMEM;
> >
> > +     if (add_uevent_var(env, "HID_FIRMWARE_VERSION=%04X", hdev->version))
> > +             return -ENOMEM;
> > +
> >       if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
> >                          hdev->bus, hdev->group, hdev->vendor, hdev->product))
> >               return -ENOMEM;
>
> Isn't this in
>
> hid.git#for-7.1/lenovo-v2

^ permalink raw reply

* Re: [PATCH 4/4] HID: core: Export device version via HID_FIRMWARE_VERSION uevent
From: Mario Limonciello @ 2026-03-13 17:59 UTC (permalink / raw)
  To: Daniel Schaefer, linux-input
  Cc: Richard Hughes, Jiri Kosina, Benjamin Tissoires, linux
In-Reply-To: <20260313175659.268094-5-dhs@frame.work>



On 3/13/2026 12:56 PM, Daniel Schaefer wrote:
> Expose the HID device version to userspace via the new
> HID_FIRMWARE_VERSION uevent property. This enables userspace tools
> (such as fwupd and hidapi) to retrieve device firmware version
> information, providing parity with Windows HidD_GetAttributes() API
> which returns VID, PID, and VersionNumber.
> 
> The version is exported as a 4-digit uppercase hexadecimal value
> (e.g., "0100" for version 1.0), consistent with how USB devices
> report bcdDevice.
> 
> fwupd can handle this since:
> https://github.com/fwupd/fwupd/commit/fb0d4cc98abe253003ea0e1837277fd42971e0de
> But the kernel hasn't yet exposed this.
> 
> hidapi patch is in-flight: https://github.com/libusb/hidapi/pull/777
> 
> Cc: Richard Hughes <richard@hughsie.com>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Cc: Jiri Kosina <jikos@kernel.org>
> Cc: Benjamin Tissoires <bentiss@kernel.org>
> Cc: linux@frame.work
> Signed-off-by: Daniel Schaefer <dhs@frame.work>
> ---
>   drivers/hid/hid-core.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index da57cbf0af26..c2075d5b40c3 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -2884,6 +2884,9 @@ static int hid_uevent(const struct device *dev, struct kobj_uevent_env *env)
>   	if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
>   		return -ENOMEM;
>   
> +	if (add_uevent_var(env, "HID_FIRMWARE_VERSION=%04X", hdev->version))
> +		return -ENOMEM;
> +
>   	if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
>   			   hdev->bus, hdev->group, hdev->vendor, hdev->product))
>   		return -ENOMEM;

Isn't this in

hid.git#for-7.1/lenovo-v2

^ permalink raw reply

* [PATCH 4/4] HID: core: Export device version via HID_FIRMWARE_VERSION uevent
From: Daniel Schaefer @ 2026-03-13 17:56 UTC (permalink / raw)
  To: linux-input
  Cc: Daniel Schaefer, Richard Hughes, Mario Limonciello, Jiri Kosina,
	Benjamin Tissoires, linux
In-Reply-To: <20260313175659.268094-1-dhs@frame.work>

Expose the HID device version to userspace via the new
HID_FIRMWARE_VERSION uevent property. This enables userspace tools
(such as fwupd and hidapi) to retrieve device firmware version
information, providing parity with Windows HidD_GetAttributes() API
which returns VID, PID, and VersionNumber.

The version is exported as a 4-digit uppercase hexadecimal value
(e.g., "0100" for version 1.0), consistent with how USB devices
report bcdDevice.

fwupd can handle this since:
https://github.com/fwupd/fwupd/commit/fb0d4cc98abe253003ea0e1837277fd42971e0de
But the kernel hasn't yet exposed this.

hidapi patch is in-flight: https://github.com/libusb/hidapi/pull/777

Cc: Richard Hughes <richard@hughsie.com>
Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux@frame.work
Signed-off-by: Daniel Schaefer <dhs@frame.work>
---
 drivers/hid/hid-core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index da57cbf0af26..c2075d5b40c3 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2884,6 +2884,9 @@ static int hid_uevent(const struct device *dev, struct kobj_uevent_env *env)
 	if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
 		return -ENOMEM;
 
+	if (add_uevent_var(env, "HID_FIRMWARE_VERSION=%04X", hdev->version))
+		return -ENOMEM;
+
 	if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
 			   hdev->bus, hdev->group, hdev->vendor, hdev->product))
 		return -ENOMEM;
-- 
2.52.0


^ permalink raw reply related

* [PATCH 3/4] HID: surface: Use device version instead of HID spec version
From: Daniel Schaefer @ 2026-03-13 17:56 UTC (permalink / raw)
  To: linux-input
  Cc: Daniel Schaefer, Maximilian Luz, Jiri Kosina, Benjamin Tissoires
In-Reply-To: <20260313175659.268094-1-dhs@frame.work>

Use attrs.version instead of hid_desc.hid_version for hid->version.
The driver has two structures with version information:

  - hid_desc.hid_version: HID specification version
  - attrs.version: Device-specific version number

The current code incorrectly uses hid_version from the HID descriptor,
which reports the HID spec version rather than the actual device
version. This change aligns with how other HID drivers report device
version and matches the attrs structure which already provides vendor
and product IDs.

Cc: Maximilian Luz <luzmaximilian@gmail.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Signed-off-by: Daniel Schaefer <dhs@frame.work>
---
 drivers/hid/surface-hid/surface_hid_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c
index 6690c24f28f0..e31d6597bc9b 100644
--- a/drivers/hid/surface-hid/surface_hid_core.c
+++ b/drivers/hid/surface-hid/surface_hid_core.c
@@ -206,7 +206,7 @@ int surface_hid_device_add(struct surface_hid_device *shid)
 	shid->hid->bus = BUS_HOST;
 	shid->hid->vendor = get_unaligned_le16(&shid->attrs.vendor);
 	shid->hid->product = get_unaligned_le16(&shid->attrs.product);
-	shid->hid->version = get_unaligned_le16(&shid->hid_desc.hid_version);
+	shid->hid->version = get_unaligned_le16(&shid->attrs.version);
 	shid->hid->country = shid->hid_desc.country_code;
 
 	snprintf(shid->hid->name, sizeof(shid->hid->name), "Microsoft Surface %04X:%04X",
-- 
2.52.0


^ permalink raw reply related

* [PATCH 2/4] HID: goodix-spi: Use version_id for device version
From: Daniel Schaefer @ 2026-03-13 17:56 UTC (permalink / raw)
  To: linux-input
  Cc: Daniel Schaefer, Charles Wang, Jiri Kosina, Benjamin Tissoires
In-Reply-To: <20260313175659.268094-1-dhs@frame.work>

Use version_id instead of bcd_version for hid->version. The HID
descriptor contains two version fields:

  - bcd_version: HID specification version (e.g., 0x0100 for HID 1.0)
  - version_id: Device-specific version number

The current code incorrectly uses bcd_version, which reports the HID
spec version rather than the actual device/firmware version.

Cc: Charles Wang <charles.goodix@gmail.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Signed-off-by: Daniel Schaefer <dhs@frame.work>
---
 drivers/hid/hid-goodix-spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c
index 80c0288a3a38..cbe95e0f6ce4 100644
--- a/drivers/hid/hid-goodix-spi.c
+++ b/drivers/hid/hid-goodix-spi.c
@@ -653,7 +653,7 @@ static int goodix_hid_init(struct goodix_ts_data *ts)
 	hid->bus = BUS_SPI;
 	hid->dev.parent = &ts->spi->dev;
 
-	hid->version = le16_to_cpu(ts->hid_desc.bcd_version);
+	hid->version = le16_to_cpu(ts->hid_desc.version_id);
 	hid->vendor = le16_to_cpu(ts->hid_desc.vendor_id);
 	hid->product = le16_to_cpu(ts->hid_desc.product_id);
 	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-gdix",
-- 
2.52.0


^ permalink raw reply related

* [PATCH 1/4] HID: i2c-hid: Use wVersionID for device version
From: Daniel Schaefer @ 2026-03-13 17:56 UTC (permalink / raw)
  To: linux-input; +Cc: Daniel Schaefer, Jiri Kosina, Benjamin Tissoires, linux
In-Reply-To: <20260313175659.268094-1-dhs@frame.work>

Use wVersionID instead of bcdVersion for hid->version. Per the HID
over I2C Protocol Specification (Rev 1.0, Section 4.2), the HID
descriptor contains two version fields with distinct purposes:

  - bcdVersion: HID specification version (always 0x0100 for HID 1.0)
  - wVersionID: Device-specific version number

The current code incorrectly uses bcdVersion, which always reports
the HID spec version rather than the actual device/firmware version.
This change aligns I2C HID behavior with USB HID, which correctly
uses bcdDevice (the device version) for hid->version.

Currently wVersionID is not exposed to userspace at all. It is useful
because some firmwares use this as their firmware version. It's not
possible to check those device's firmware version on Linux, only
Windows.

Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Cc: linux@frame.work
Signed-off-by: Daniel Schaefer <dhs@frame.work>
---
 drivers/hid/i2c-hid/i2c-hid-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 5a183af3d5c6..41327e32f359 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -1056,7 +1056,7 @@ static int __i2c_hid_core_probe(struct i2c_hid *ihid)
 		return ret;
 	}
 
-	hid->version = le16_to_cpu(ihid->hdesc.bcdVersion);
+	hid->version = le16_to_cpu(ihid->hdesc.wVersionID);
 	hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
 	hid->product = le16_to_cpu(ihid->hdesc.wProductID);
 
-- 
2.52.0


^ permalink raw reply related

* [PATCH 0/4] HID: Use wVersionID for device version
From: Daniel Schaefer @ 2026-03-13 17:56 UTC (permalink / raw)
  To: linux-input
  Cc: Daniel Schaefer, Jiri Kosina, Benjamin Tissoires, linux,
	Mario Limonciello, Maximilian Luz, Richard Hughes, Charles Wang

The motivation for this patch series is that the touchpads on Framework
Laptops expose their firmware version in the I2C HID device descriptor.
So the vendor's windows tool uses that to check the firmware version,
but Linux does not expose it to userspace at all.
We have added vendor specific HID reports to newer firmware for reading
the firmware version -that means however, the old firmware still cannot
reports its version to Linux at all.

I found that Mario has been planning to add a way for the kernel to
report HID firmware versions to userspace and added support to fwupd.
There's a kernel patch in flight that also exports this:
https://lwn.net/ml/all/20260220070533.4083667-1-derekjohn.clark@gmail.com/

While adding this for I2C HID devices, I noticed that the goodix-spi and
surface drivers also expose the HID protocol version, which is not very
useful. I do not have hardware to test those

The i2c-hid and core changes were tested on Framework Laptop 16.
I also added support to hidapi for reading the new uevent, if not
provided by USB already: https://github.com/libusb/hidapi/pull/777

Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Cc: linux@frame.work
Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Maximilian Luz <luzmaximilian@gmail.com>
Cc: Richard Hughes <richard@hughsie.com>
Cc: Charles Wang <charles.goodix@gmail.com>

Daniel Schaefer (4):
  HID: i2c-hid: Use wVersionID for device version
  HID: goodix-spi: Use version_id for device version
  HID: surface: Use device version instead of HID spec version
  HID: core: Export device version via HID_FIRMWARE_VERSION uevent

 drivers/hid/hid-core.c                     | 3 +++
 drivers/hid/hid-goodix-spi.c               | 2 +-
 drivers/hid/i2c-hid/i2c-hid-core.c         | 2 +-
 drivers/hid/surface-hid/surface_hid_core.c | 2 +-
 4 files changed, 6 insertions(+), 3 deletions(-)

-- 
2.52.0


^ permalink raw reply

* Re: [PATCH] dt-bindings: touchscreen: trivial-touch: Move allOf: after required:
From: Conor Dooley @ 2026-03-13 17:29 UTC (permalink / raw)
  To: Marek Vasut
  Cc: devicetree, Conor Dooley, Dmitry Torokhov, Frank Li, Job Noorman,
	Krzysztof Kozlowski, Rob Herring, linux-input, linux-renesas-soc
In-Reply-To: <20260312224925.186077-1-marek.vasut+renesas@mailbox.org>

[-- Attachment #1: Type: text/plain, Size: 673 bytes --]

On Thu, Mar 12, 2026 at 11:49:01PM +0100, Marek Vasut wrote:
> Majority of schemas place allOf: after required: . Documentation
> Documentation/devicetree/bindings/writing-schema.rst also hints at
> this ordering. Trivially update this schema. No functional change.
> 
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> ---
> NOTE: This comes from https://lore.kernel.org/all/20260117-grinning-heavy-crab-11f245@quoll/
>       where krzk comments "allOf: should be placed after required: block."

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

Certainly not expecting a new version for the "nits" provided by Frank.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v6 4/4] Input: Add TouchNetix aXiom I2C Touchscreen support
From: Andrew Thomas @ 2026-03-13 17:07 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Luis Chamberlain, Russ Weight, Greg Kroah-Hartman,
	Rafael J. Wysocki, Andrew Morton, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Kamel Bouhara,
	Marco Felsch, Henrik Rydberg, Danilo Krummrich, linux-kernel,
	devicetree, linux-input
In-Reply-To: <20260303-v6-10-topic-touchscreen-axiom-v6-4-8ac755add12b@pengutronix.de>

On Tue, Mar 03, 2026 at 11:41:22PM +0100, Marco Felsch wrote:
>This adds the initial support for the TouchNetix AX54A touchcontroller
>which is part of TouchNetix's aXiom touchscreen controller family.
>
>The TouchNetix aXiom family provides two physical interfaces: SPI and
>I2C. This patch covers only the I2C interface.
>
>Apart the input event handling the driver supports firmware updates too.
>One firmware interface handles the touchcontroller firmware (AXFW)
>update the other handles the touchcontroller configuration (TH2CFGBIN)
>update.
>
>Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
>---
> .../testing/sysfs-driver-input-touchnetix-axiom    |   80 +
> drivers/input/touchscreen/Kconfig                  |   17 +
> drivers/input/touchscreen/Makefile                 |    1 +
> drivers/input/touchscreen/touchnetix_axiom.c       | 3084 ++++++++++++++++++++
> 4 files changed, 3182 insertions(+)
>
>diff --git a/Documentation/ABI/testing/sysfs-driver-input-touchnetix-axiom b/Documentation/ABI/testing/sysfs-driver-input-touchnetix-axiom
>new file mode 100644
>index 0000000000000000000000000000000000000000..8262673630557bf1e595a97ec23e66c1c5370f71
>--- /dev/null
>+++ b/Documentation/ABI/testing/sysfs-driver-input-touchnetix-axiom
>@@ -0,0 +1,80 @@
>+What:		/sys/bus/i2c/devices/xxx/fw_major
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the firmware major version provided by the touchscreen.
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/fw_minor
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the firmware minor version provided by the touchscreen.
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/fw_rc
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the firmware release canidate version provided by the touchscreen.
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/fw_status
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the firmware status provided by the touchscreen. It may
>+		be either "release" or "engineering".
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/fw_variant
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the firmware variant provided by the touchscreen. It may
>+		be either: "0d", "2d", "3d", "force", "xl" or "unknown".
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/device_id
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the touchscreen device id, for example: "54" for the AX54A.
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>+
>+What:		/sys/bus/i2c/devices/xxx/device_state
>+Date:		Jan 2026
>+Contact:	linux-input@vger.kernel.org
>+Description:
>+		Reports the touchscreen device current runtime state. The
>+		following values are reported:
>+
>+		discovery: Device is in discovery mode.
>+		tcp:  Device is in touch-control-protocol (tcp) mode. This is
>+		      the normal working mode.
>+		th2cfg-update: Device is in configuration update mode.
>+		bootloader: Device is in bootloader mode, used for firmware
>+			    updates.
>+		unknown: Device mode is unknown.
>+
>+		Access: Read
>+
>+		Valid values: Represented as string
>diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>index 196905162945d59e775c3e0bff6540a82842229a..9263dd79dab7e518e27af35364fcebbff0ba706e 100644
>--- a/drivers/input/touchscreen/Kconfig
>+++ b/drivers/input/touchscreen/Kconfig
>@@ -806,6 +806,23 @@ config TOUCHSCREEN_MIGOR
> 	  To compile this driver as a module, choose M here: the
> 	  module will be called migor_ts.
>
>+config TOUCHSCREEN_TOUCHNETIX_AXIOM
>+	tristate "TouchNetix aXiom based touchscreen controllers"
>+	# We need to call into panel code so if DRM=m, this can't be 'y'
>+	depends on DRM || !DRM
>+	depends on I2C
>+	select CRC16
>+	select CRC32
>+	select REGMAP_I2C
>+	help
>+	  Say Y here if you have a axiom touchscreen connected to
>+	  your system.
>+
>+	  If unsure, say N.
>+
>+	  To compile this driver as a module, choose M here: the
>+	  module will be called touchnetix_axiom.
>+
> config TOUCHSCREEN_TOUCHRIGHT
> 	tristate "Touchright serial touchscreen"
> 	select SERIO
>diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>index 97a025c6a3770fb80255246eb63c11688ebd79eb..0591cb304784699bf2a8bda204461ac5f4532bb1 100644
>--- a/drivers/input/touchscreen/Makefile
>+++ b/drivers/input/touchscreen/Makefile
>@@ -88,6 +88,7 @@ obj-$(CONFIG_TOUCHSCREEN_SUR40)		+= sur40.o
> obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI)	+= surface3_spi.o
> obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)	+= ti_am335x_tsc.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
>+obj-$(CONFIG_TOUCHSCREEN_TOUCHNETIX_AXIOM)	+= touchnetix_axiom.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o
> obj-$(CONFIG_TOUCHSCREEN_TS4800)	+= ts4800-ts.o
>diff --git a/drivers/input/touchscreen/touchnetix_axiom.c b/drivers/input/touchscreen/touchnetix_axiom.c
>new file mode 100644
>index 0000000000000000000000000000000000000000..d909b108ee24dfc5a56b0ba735cb8a7882612d34
>--- /dev/null
>+++ b/drivers/input/touchscreen/touchnetix_axiom.c
>@@ -0,0 +1,3084 @@
>+// SPDX-License-Identifier: GPL-2.0-only
>+/*
>+ * TouchNetix aXiom Touchscreen Driver
>+ *
>+ * Copyright (C) 2024 Pengutronix
>+ *
>+ * Marco Felsch <kernel@pengutronix.de>
>+ */
>+
>+#include <drm/drm_panel.h>
>+#include <linux/bitfield.h>
>+#include <linux/bits.h>
>+#include <linux/completion.h>
>+#include <linux/crc16.h>
>+#include <linux/crc32.h>
>+#include <linux/delay.h>

...

>+static int axiom_u02_enter_bootloader(struct axiom_data *ts)
>+{
>+	struct axiom_u02_rev1_system_manager_msg msg = { };
>+	struct device *dev = ts->dev;
>+	unsigned int val;
>+	int error;
>+
>+	if (!axiom_driver_supports_usage(ts, AXIOM_U02))
>+		return -EINVAL;
>+
>+	/*
>+	 * Enter the bootloader mode requires 3 consecutive messages so we can't
>+	 * check for the response.
>+	 * TODO: Check if it's required to add a delay between the consecutive
>+	 * CMD_ENTERBOOTLOADER cmds.
>+	 */
>+	msg.command = cpu_to_le16(AXIOM_U02_REV1_CMD_ENTERBOOTLOADER);
>+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY1);
>+	error = axiom_u02_send_msg(ts, &msg, false);

As mentioned before the delay between commands is too short and the next command is sent
before u02 is ready, which means the driver fails to put axiom into the bootloader.
Have you tested with an i2c speed of 400KHz?
All you need is to put true in above to wait for the bootloader command.
error = axiom_u02_send_msg(ts, &msg, true);

Just dont do it for the last command.

I am not too sure why you are having issues with this, this is how we do it for all our devices.

>+	if (error) {
>+		dev_err(dev, "Failed to send bootloader-key1: %d\n", error);
>+		return error;
>+	}
>+
>+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY2);
>+	error = axiom_u02_send_msg(ts, &msg, false);

Here also.

>+	if (error) {
>+		dev_err(dev, "Failed to send bootloader-key2: %d\n", error);
>+		return error;
>+	}
>+
>+	msg.parameters[0] = cpu_to_le16(AXIOM_U02_REV1_PARAM0_ENTERBOOLOADER_KEY3);
>+	error = axiom_u02_send_msg(ts, &msg, false);
>+	if (error) {
>+		dev_err(dev, "Failed to send bootloader-key3: %d\n", error);
>+		return error;
>+	}
>+
>+	/* Sleep before the first read to give the device time */
>+	fsleep(250 * USEC_PER_MSEC);
>+
>+	/* Wait till the device reports it is in bootloader mode */
>+	error = regmap_read_poll_timeout(ts->regmap,
>+					 AXIOM_U31_REV1_DEVICE_ID_HIGH_REG, val,
>+					 FIELD_GET(AXIOM_U31_REV1_MODE_MASK, val) ==
>+						AXIOM_U31_REV1_MODE_BLP,
>+					 250 * USEC_PER_MSEC, USEC_PER_SEC);
>+	if (error)
>+		return error;
>+
>+	return 0;
>+}
>+

...


Other than the above comments I have no issues with the driver.
We can support more usages in a later patch.

Many Thanks,
Andrew


^ permalink raw reply

* Re: [PATCH 2/4] HID: bpf: prevent buffer overflow in hid_hw_request
From: Jiri Kosina @ 2026-03-13 15:58 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Shuah Khan, linux-input, linux-kselftest, linux-kernel, stable
In-Reply-To: <20260313-wip-bpf-fixes-v1-2-74b860315060@kernel.org>

On Fri, 13 Mar 2026, Benjamin Tissoires wrote:

> right now the returned value is considered to be always valid. However,
> when playing with HID-BPF, the return value can be arbitrary big,
> because it's the return value of dispatch_hid_bpf_raw_requests(), which
> calls the struct_ops and we have no guarantees that the value makes
> sense.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

Acked-by: Jiri Kosina <jkosina@suse.com>

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH 1/4] selftests/hid: fix compilation when bpf_wq and hid_device are not exported
From: Jiri Kosina @ 2026-03-13 15:58 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Shuah Khan, linux-input, linux-kselftest, linux-kernel,
	kernel test robot, stable
In-Reply-To: <20260313-wip-bpf-fixes-v1-1-74b860315060@kernel.org>

On Fri, 13 Mar 2026, Benjamin Tissoires wrote:

> This can happen in situations when CONFIG_HID_SUPPORT is set to no, or
> some complex situations where struct bpf_wq is not exported.
> 
> So do the usual dance of hiding them before including vmlinux.h, and
> then redefining them and make use of CO-RE to have the correct offsets.
> 
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202603111558.KLCIxsZB-lkp@intel.com/
> Cc: stable@vger.kernel.org
> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

Acked-by: Jiri Kosina <jkosina@suse.com>

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH] dt-bindings: touchscreen: trivial-touch: Move allOf: after required:
From: Frank Li @ 2026-03-13 14:56 UTC (permalink / raw)
  To: Marek Vasut
  Cc: devicetree, Conor Dooley, Dmitry Torokhov, Job Noorman,
	Krzysztof Kozlowski, Rob Herring, linux-input, linux-renesas-soc
In-Reply-To: <20260312224925.186077-1-marek.vasut+renesas@mailbox.org>

On Thu, Mar 12, 2026 at 11:49:01PM +0100, Marek Vasut wrote:
> Majority of schemas place allOf: after required: . Documentation

Nit: If there special char, suggest use 'allOf:' 'required:'. "Documentation"
is reduntant.

Just said "writing-schema.rst hints this order".

Reviewed-by: Frank Li <Frank.Li@nxp.com>

> Documentation/devicetree/bindings/writing-schema.rst also hints at
> this ordering. Trivially update this schema. No functional change.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> ---
> NOTE: This comes from https://lore.kernel.org/all/20260117-grinning-heavy-crab-11f245@quoll/
>       where krzk comments "allOf: should be placed after required: block."
> ---
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: Frank Li <Frank.Li@nxp.com>
> Cc: Job Noorman <job@noorman.info>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Rob Herring <robh@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-input@vger.kernel.org
> Cc: linux-renesas-soc@vger.kernel.org
> ---
>  .../bindings/input/touchscreen/trivial-touch.yaml           | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> index 6441d21223caf..6316a8d32f39b 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
> @@ -53,14 +53,14 @@ properties:
>
>    wakeup-source: true
>
> -allOf:
> -  - $ref: touchscreen.yaml
> -
>  required:
>    - compatible
>    - reg
>    - interrupts
>
> +allOf:
> +  - $ref: touchscreen.yaml
> +
>  unevaluatedProperties: false
>
>  examples:
> --
> 2.51.0
>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox