Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH AUTOSEL 6.9 42/44] input: Add event code for accessibility key
From: Sasha Levin @ 2024-06-18 12:35 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Aseda Aboagye, Dmitry Torokhov, Benjamin Tissoires, Sasha Levin,
	jikos, linux-input
In-Reply-To: <20240618123611.3301370-1-sashal@kernel.org>

From: Aseda Aboagye <aaboagye@chromium.org>

[ Upstream commit 0c7dd00de018ff70b3452c424901816e26366a8a ]

HUTRR116 added support for a new usage titled "System Accessibility
Binding" which toggles a system-wide bound accessibility UI or command.
This commit simply adds a new event code for the usage.

Signed-off-by: Aseda Aboagye <aaboagye@chromium.org>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/Zl-e97O9nvudco5z@google.com
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/hid/hid-debug.c                | 1 +
 drivers/hid/hid-input.c                | 1 +
 include/uapi/linux/input-event-codes.h | 1 +
 3 files changed, 3 insertions(+)

diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 7dd83ec74f8a9..c629ab161d5b2 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -974,6 +974,7 @@ static const char *keys[KEY_MAX + 1] = {
 	[KEY_CAMERA_ACCESS_ENABLE] = "CameraAccessEnable",
 	[KEY_CAMERA_ACCESS_DISABLE] = "CameraAccessDisable",
 	[KEY_CAMERA_ACCESS_TOGGLE] = "CameraAccessToggle",
+	[KEY_ACCESSIBILITY] = "Accessibility",
 	[KEY_DICTATE] = "Dictate",
 	[KEY_MICMUTE] = "MicrophoneMute",
 	[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index e03d300d2bac4..d5a6e89c3086e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -836,6 +836,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 		if ((usage->hid & 0xf0) == 0xa0) {	/* SystemControl */
 			switch (usage->hid & 0xf) {
 			case 0x9: map_key_clear(KEY_MICMUTE); break;
+			case 0xa: map_key_clear(KEY_ACCESSIBILITY); break;
 			default: goto ignore;
 			}
 			break;
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 03edf2ccdf6c8..39f11ec676fae 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -618,6 +618,7 @@
 #define KEY_CAMERA_ACCESS_ENABLE	0x24b	/* Enables programmatic access to camera devices. (HUTRR72) */
 #define KEY_CAMERA_ACCESS_DISABLE	0x24c	/* Disables programmatic access to camera devices. (HUTRR72) */
 #define KEY_CAMERA_ACCESS_TOGGLE	0x24d	/* Toggles the current state of the camera access control. (HUTRR72) */
+#define KEY_ACCESSIBILITY		0x24e	/* Toggles the system bound accessibility UI/command (HUTRR116) */
 
 #define KEY_BRIGHTNESS_MIN		0x250	/* Set Brightness to Minimum */
 #define KEY_BRIGHTNESS_MAX		0x251	/* Set Brightness to Maximum */
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.9 32/44] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-18 12:35 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240618123611.3301370-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 62f562ad50263..050fa9ca4ec94 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -71,7 +71,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -136,7 +135,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	touchscreen_parse_properties(data->input, true, &data->prop);
 	silead_apply_efi_fw_min_max(data);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -256,10 +255,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	if (silead_ts_handle_pen_data(data, buf))
@@ -315,7 +314,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -325,7 +323,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -591,13 +589,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* Re: Advise needed on stale patches
From: Francesco Dolcini @ 2024-06-18 10:10 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Francesco Dolcini, linux-input, Stefan Eichenberger,
	Emanuele Ghidoli
In-Reply-To: <ZfSZDbyczmodyI_j@google.com>

Hello again Dmitry and Linux Input people,

On Fri, Mar 15, 2024 at 11:53:01AM -0700, Dmitry Torokhov wrote:
> On Fri, Mar 15, 2024 at 10:33:07AM +0100, Francesco Dolcini wrote:
> > Hello Dmitry and Linux Input people,
> > 
> > In the last months I sent (or was involved in) a couple of small patches
> > [1][2] (bug fixes or small addition to an existing driver) and they have
> > been around in the mailing list for quite some time (months, 2023-09-20
> > the oldest one).
> > 
> > I am not sure on how to progress here, therefore looking for some advise.
> > 
> > Maybe they did just fall through the cracks, in this case just take this
> > as a kind head up (or maybe those email did not pass some aggressive
> > spam filtering?).
> > 
> > Or maybe the changes are not deemed correct or something wrong was done,
> > and in this case it would be great to know what we could improve.
> > 
> > Or, maybe you just had other priorities (life and work are challenging
> > at times, I know), in this case, if possible, I would love to know if I
> > can provide some small help in any way.
> 
> Sorry, I am swamped with other projects. I just responded on the
> mailing list for the patch [2].

You got a new patch version 2 months ago and no comment afterward.

What about https://lore.kernel.org/all/20231222183114.30775-1-francesco@dolcini.it/ ?
Those are just a couple of small fixes that should be easy to provide a
feedback on, or eventually just apply? That one is on the LKML since
September 2023.

With that said, sorry for buggering you again, I understand that you
might have other project and priorities, however I do not know how to
move forward.

In the end what I am looking for is some guidance on what's the best way
to contribute in an effective way such kind of small fixes/improvements
to the Linux input subsystem drivers.

Thanks
Francesco


^ permalink raw reply

* Re: [PATCH AUTOSEL 5.10 4/8] platform/x86: touchscreen_dmi: Add support for setting touchscreen properties from cmdline
From: Pavel Machek @ 2024-06-18  9:06 UTC (permalink / raw)
  To: Sasha Levin
  Cc: linux-kernel, stable, Hans de Goede, Gregor Riepl, corbet,
	ilpo.jarvinen, paulmck, jpoimboe, tglx, bp, xiongwei.song,
	linux-doc, linux-input, platform-driver-x86
In-Reply-To: <20240605120554.2968012-4-sashal@kernel.org>

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

Hi!

> [ Upstream commit 0b178b02673998f5acca5a0365a8858ca45beedb ]
> 
> On x86/ACPI platforms touchscreens mostly just work without needing any
> device/model specific configuration. But in some cases (mostly with Silead
> and Goodix touchscreens) it is still necessary to manually specify various
> touchscreen-properties on a per model basis.
> 
> touchscreen_dmi is a special place for DMI quirks for this, but it can be
> challenging for users to figure out the right property values, especially
> for Silead touchscreens where non of these can be read back from
> the touchscreen-controller.
> 
> ATM users can only test touchscreen properties by editing touchscreen_dmi.c
> and then building a completely new kernel which makes it unnecessary
> difficult for users to test and submit properties when necessary for their
> laptop / tablet model.
> 
> Add support for specifying properties on the kernel commandline to allow
> users to easily figure out the right settings. See the added documentation
> in kernel-parameters.txt for the commandline syntax.

I don't believe this is suitable for stable.

Best regards,
								Pavel
-- 
People of Russia, stop Putin before his war on Ukraine escalates.

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

^ permalink raw reply

* [PATCH v5 2/2] dt-bindings: input: Goodix SPI HID Touchscreen
From: Charles Wang @ 2024-06-18  8:44 UTC (permalink / raw)
  To: dmitry.torokhov, dan.carpenter, conor, robh
  Cc: dianders, krzk+dt, jikos, bentiss, hbarnor, linux-input,
	devicetree, linux-kernel, Charles Wang
In-Reply-To: <20240618084455.1451461-1-charles.goodix@gmail.com>

The Goodix GT7986U touch controller report touch data according to the
HID protocol through the SPI bus. However, it is incompatible with
Microsoft's HID-over-SPI protocol.

Signed-off-by: Charles Wang <charles.goodix@gmail.com>
---
 .../bindings/input/goodix,gt7986u.yaml        | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/goodix,gt7986u.yaml

diff --git a/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml b/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
new file mode 100644
index 000000000..25a26b4ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/goodix,gt7986u.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GOODIX GT7986U SPI HID Touchscreen
+
+maintainers:
+  - Charles Wang <charles.goodix@gmail.com>
+
+description: Supports the Goodix GT7986U touchscreen.
+  This touch controller reports data packaged according to the HID protocol,
+  but is incompatible with Microsoft's HID-over-SPI protocol.
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+  compatible:
+    enum:
+      - goodix,gt7986u
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+    description: reset gpio the chip is connected to.
+
+  goodix,hid-report-addr:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      The register address for retrieving HID report data.
+      This address is related to the device firmware and may
+      change after a firmware update.
+
+  spi-max-frequency: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - reset-gpios
+  - goodix,hid-report-addr
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/gpio/gpio.h>
+
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      touchscreen@0 {
+        compatible = "goodix,gt7986u";
+        reg = <0>;
+        interrupt-parent = <&gpio>;
+        interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+        reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+        spi-max-frequency = <10000000>;
+        goodix,hid-report-addr = <0x22c8c>;
+      };
+    };
+
+...
-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 1/2] HID: hid-goodix: Add Goodix HID-over-SPI driver
From: Charles Wang @ 2024-06-18  8:44 UTC (permalink / raw)
  To: dmitry.torokhov, dan.carpenter, conor, robh
  Cc: dianders, krzk+dt, jikos, bentiss, hbarnor, linux-input,
	devicetree, linux-kernel, Charles Wang
In-Reply-To: <20240618084455.1451461-1-charles.goodix@gmail.com>

This patch introduces a new driver to support the Goodix GT7986U
touch controller. This device is not compatible with Microsoft's
HID-over-SPI protocol and therefore needs to implement its own
flavor. The data reported is packaged according to the HID
protocol but uses SPI for communication to improve speed. This
enables the device to transmit not only coordinate data but also
corresponding raw data that can be accessed by user-space programs
through the hidraw interface. The raw data can be utilized for
functions like palm rejection, thereby improving the touch experience.

Key features:
- Device connection confirmation and initialization
- IRQ-based event reporting to the input subsystem
- Support for HIDRAW operations (GET_REPORT and SET_REPORT)

Signed-off-by: Charles Wang <charles.goodix@gmail.com>
---
 drivers/hid/Kconfig          |   6 +
 drivers/hid/Makefile         |   1 +
 drivers/hid/hid-goodix-spi.c | 811 +++++++++++++++++++++++++++++++++++
 3 files changed, 818 insertions(+)
 create mode 100644 drivers/hid/hid-goodix-spi.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4c682c650..03e750e04 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -404,6 +404,12 @@ config HID_VIVALDI_COMMON
 	  option so that drivers can use common code to parse the HID
 	  descriptors for vivaldi function row keymap.
 
+config HID_GOODIX_SPI
+	tristate "Goodix GT7986U SPI HID touchscreen"
+	depends on SPI_MASTER
+	help
+	  Support for Goodix GT7986U SPI HID touchscreen device.
+
 config HID_GOOGLE_HAMMER
 	tristate "Google Hammer Keyboard"
 	select HID_VIVALDI_COMMON
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 082a728ea..56e3ed4c1 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_HID_GEMBIRD)	+= hid-gembird.o
 obj-$(CONFIG_HID_GFRM)		+= hid-gfrm.o
 obj-$(CONFIG_HID_GLORIOUS)  += hid-glorious.o
 obj-$(CONFIG_HID_VIVALDI_COMMON) += hid-vivaldi-common.o
+obj-$(CONFIG_HID_GOODIX_SPI)	+= hid-goodix-spi.o
 obj-$(CONFIG_HID_GOOGLE_HAMMER)	+= hid-google-hammer.o
 obj-$(CONFIG_HID_GOOGLE_STADIA_FF)	+= hid-google-stadiaff.o
 obj-$(CONFIG_HID_VIVALDI)	+= hid-vivaldi.o
diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c
new file mode 100644
index 000000000..da5676120
--- /dev/null
+++ b/drivers/hid/hid-goodix-spi.c
@@ -0,0 +1,811 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Goodix GT7986U SPI Driver Code for HID.
+ *
+ * Copyright (C) 2024 Godix, Inc.
+ */
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/hid.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+
+#define GOODIX_DEV_CONFIRM_ADDR		0x10000
+#define GOODIX_HID_DESC_ADDR		0x1058C
+#define GOODIX_HID_REPORT_DESC_ADDR	0x105AA
+#define GOODIX_HID_SIGN_ADDR		0x10D32
+
+#define GOODIX_HID_GET_REPORT_CMD	0x02
+#define GOODIX_HID_SET_REPORT_CMD	0x03
+
+#define GOODIX_HID_MAX_INBUF_SIZE	128
+#define GOODIX_HID_ACK_READY_FLAG	0x01
+#define GOODIX_HID_REPORT_READY_FLAG	0x80
+
+#define GOODIX_DEV_CONFIRM_VAL		0xAA
+
+#define GOODIX_SPI_WRITE_FLAG		0xF0
+#define GOODIX_SPI_READ_FLAG		0xF1
+#define GOODIX_SPI_TRANS_PREFIX_LEN	1
+#define GOODIX_REGISTER_WIDTH		4
+#define GOODIX_SPI_READ_DUMMY_LEN	3
+#define GOODIX_SPI_READ_PREFIX_LEN	(GOODIX_SPI_TRANS_PREFIX_LEN + \
+					 GOODIX_REGISTER_WIDTH + \
+					 GOODIX_SPI_READ_DUMMY_LEN)
+#define GOODIX_SPI_WRITE_PREFIX_LEN	(GOODIX_SPI_TRANS_PREFIX_LEN + \
+					 GOODIX_REGISTER_WIDTH)
+
+#define GOODIX_CHECKSUM_SIZE		sizeof(u16)
+#define GOODIX_NORMAL_RESET_DELAY_MS	150
+
+struct goodix_hid_report_header {
+	u8 flag;
+	__le16 size;
+} __packed;
+#define GOODIX_HID_ACK_HEADER_SIZE	sizeof(struct goodix_hid_report_header)
+
+struct goodix_hid_report_package {
+	__le16 size;
+	u8 data[];
+};
+
+#define GOODIX_HID_PKG_LEN_SIZE		sizeof(u16)
+#define GOODIX_HID_COOR_DATA_LEN	82
+#define GOODIX_HID_COOR_PKG_LEN		(GOODIX_HID_PKG_LEN_SIZE + \
+					 GOODIX_HID_COOR_DATA_LEN)
+
+/* power state */
+#define GOODIX_SPI_POWER_ON		0x00
+#define GOODIX_SPI_POWER_SLEEP		0x01
+
+/* flags used to record the current device operating state */
+#define GOODIX_HID_STARTED		0
+
+struct goodix_hid_report_event {
+	struct goodix_hid_report_header hdr;
+	u8 data[GOODIX_HID_COOR_PKG_LEN];
+} __packed;
+
+struct goodix_hid_desc {
+	__le16 desc_length;
+	__le16 bcd_version;
+	__le16 report_desc_length;
+	__le16 report_desc_register;
+	__le16 input_register;
+	__le16 max_input_length;
+	__le16 output_register;
+	__le16 max_output_length;
+	__le16 cmd_register;
+	__le16 data_register;
+	__le16 vendor_id;
+	__le16 product_id;
+	__le16 version_id;
+	__le32 reserved;
+} __packed;
+
+struct goodix_ts_data {
+	struct device *dev;
+	struct spi_device *spi;
+	struct hid_device *hid;
+	struct goodix_hid_desc hid_desc;
+
+	struct gpio_desc *reset_gpio;
+	u32 hid_report_addr;
+
+	unsigned long flags;
+	/* lock for hid raw request operation */
+	struct mutex hid_request_lock;
+	/* buffer used to store hid report event */
+	u8 *event_buf;
+	u32 hid_max_event_sz;
+	/* buffer used to do spi data transfer */
+	u8 xfer_buf[SZ_2K] ____cacheline_aligned;
+};
+
+static void *goodix_get_event_report(struct goodix_ts_data *ts, u32 addr,
+				     u8 *data, size_t len)
+{
+	struct spi_device *spi = to_spi_device(&ts->spi->dev);
+	struct spi_transfer xfers;
+	struct spi_message spi_msg;
+	int error;
+
+	/* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */
+	data[0] = GOODIX_SPI_READ_FLAG;
+	put_unaligned_be32(addr, data + GOODIX_SPI_TRANS_PREFIX_LEN);
+
+	spi_message_init(&spi_msg);
+	memset(&xfers, 0, sizeof(xfers));
+	xfers.tx_buf = data;
+	xfers.rx_buf = data;
+	xfers.len = GOODIX_SPI_READ_PREFIX_LEN + len;
+	spi_message_add_tail(&xfers, &spi_msg);
+
+	error = spi_sync(spi, &spi_msg);
+	if (error) {
+		dev_err(ts->dev, "spi transfer error: %d", error);
+		return NULL;
+	}
+
+	return data + GOODIX_SPI_READ_PREFIX_LEN;
+}
+
+static int goodix_spi_read(struct goodix_ts_data *ts, u32 addr,
+			   void *data, size_t len)
+{
+	struct spi_device *spi = to_spi_device(&ts->spi->dev);
+	struct spi_transfer xfers;
+	struct spi_message spi_msg;
+	int error;
+
+	if (GOODIX_SPI_READ_PREFIX_LEN + len > sizeof(ts->xfer_buf)) {
+		dev_err(ts->dev, "read data len exceed limit %zu",
+			sizeof(ts->xfer_buf) - GOODIX_SPI_READ_PREFIX_LEN);
+		return -EINVAL;
+	}
+
+	/* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */
+	ts->xfer_buf[0] = GOODIX_SPI_READ_FLAG;
+	put_unaligned_be32(addr, ts->xfer_buf + GOODIX_SPI_TRANS_PREFIX_LEN);
+
+	spi_message_init(&spi_msg);
+	memset(&xfers, 0, sizeof(xfers));
+	xfers.tx_buf = ts->xfer_buf;
+	xfers.rx_buf = ts->xfer_buf;
+	xfers.len = GOODIX_SPI_READ_PREFIX_LEN + len;
+	spi_message_add_tail(&xfers, &spi_msg);
+
+	error = spi_sync(spi, &spi_msg);
+	if (error)
+		dev_err(ts->dev, "spi transfer error: %d", error);
+	else
+		memcpy(data, ts->xfer_buf + GOODIX_SPI_READ_PREFIX_LEN, len);
+
+	return error;
+}
+
+static int goodix_spi_write(struct goodix_ts_data *ts, u32 addr,
+			    const void *data, size_t len)
+{
+	struct spi_device *spi = to_spi_device(&ts->spi->dev);
+	struct spi_transfer xfers;
+	struct spi_message spi_msg;
+	int error;
+
+	if (GOODIX_SPI_WRITE_PREFIX_LEN + len > sizeof(ts->xfer_buf)) {
+		dev_err(ts->dev, "write data len exceed limit %zu",
+			sizeof(ts->xfer_buf) - GOODIX_SPI_WRITE_PREFIX_LEN);
+		return -EINVAL;
+	}
+
+	/* buffer format: 0xF0 + addr(4bytes) + data */
+	ts->xfer_buf[0] = GOODIX_SPI_WRITE_FLAG;
+	put_unaligned_be32(addr, ts->xfer_buf + GOODIX_SPI_TRANS_PREFIX_LEN);
+	memcpy(ts->xfer_buf + GOODIX_SPI_WRITE_PREFIX_LEN, data, len);
+
+	spi_message_init(&spi_msg);
+	memset(&xfers, 0, sizeof(xfers));
+	xfers.tx_buf = ts->xfer_buf;
+	xfers.len = GOODIX_SPI_WRITE_PREFIX_LEN + len;
+	spi_message_add_tail(&xfers, &spi_msg);
+
+	error = spi_sync(spi, &spi_msg);
+	if (error)
+		dev_err(ts->dev, "spi transfer error: %d", error);
+
+	return error;
+}
+
+static int goodix_dev_confirm(struct goodix_ts_data *ts)
+{
+	u8 tx_buf[8], rx_buf[8];
+	int retry = 3;
+	int error;
+
+	gpiod_set_value_cansleep(ts->reset_gpio, 0);
+	usleep_range(4000, 4100);
+
+	memset(tx_buf, GOODIX_DEV_CONFIRM_VAL, sizeof(tx_buf));
+	while (retry--) {
+		error = goodix_spi_write(ts, GOODIX_DEV_CONFIRM_ADDR,
+					 tx_buf, sizeof(tx_buf));
+		if (error)
+			return error;
+
+		error = goodix_spi_read(ts, GOODIX_DEV_CONFIRM_ADDR,
+					rx_buf, sizeof(rx_buf));
+		if (error)
+			return error;
+
+		if (!memcmp(tx_buf, rx_buf, sizeof(tx_buf)))
+			return 0;
+
+		usleep_range(5000, 5100);
+	}
+
+	dev_err(ts->dev, "device confirm failed, rx_buf: %*ph", 8, rx_buf);
+	return -EINVAL;
+}
+
+/**
+ * goodix_hid_parse() - hid-core .parse() callback
+ * @hid: hid device instance
+ *
+ * This function gets called during call to hid_add_device
+ *
+ * Return: 0 on success and non zero on error
+ */
+static int goodix_hid_parse(struct hid_device *hid)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+	u16 rsize;
+	int error;
+
+	rsize = le16_to_cpu(ts->hid_desc.report_desc_length);
+	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+		dev_err(ts->dev, "invalid report desc size, %d", rsize);
+		return -EINVAL;
+	}
+
+	u8 *rdesc __free(kfree) = kzalloc(rsize, GFP_KERNEL);
+	if (!rdesc)
+		return -ENOMEM;
+
+	error = goodix_spi_read(ts, GOODIX_HID_REPORT_DESC_ADDR, rdesc, rsize);
+	if (error) {
+		dev_err(ts->dev, "failed get report desc, %d", error);
+		return error;
+	}
+
+	error = hid_parse_report(hid, rdesc, rsize);
+	if (error) {
+		dev_err(ts->dev, "failed parse report, %d", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int goodix_hid_get_report_length(struct hid_report *report)
+{
+	return ((report->size - 1) >> 3) + 1 +
+		report->device->report_enum[report->type].numbered + 2;
+}
+
+static void goodix_hid_find_max_report(struct hid_device *hid, unsigned int type,
+				       unsigned int *max)
+{
+	struct hid_report *report;
+	unsigned int size;
+
+	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
+		size = goodix_hid_get_report_length(report);
+		if (*max < size)
+			*max = size;
+	}
+}
+
+static int goodix_hid_start(struct hid_device *hid)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+	unsigned int bufsize = GOODIX_HID_COOR_PKG_LEN;
+
+	goodix_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize);
+	goodix_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize);
+	goodix_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize);
+
+	ts->hid_max_event_sz = GOODIX_SPI_READ_PREFIX_LEN +
+			       GOODIX_HID_ACK_HEADER_SIZE + bufsize;
+	ts->event_buf = kzalloc(ts->hid_max_event_sz, GFP_KERNEL);
+	if (!ts->event_buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void goodix_hid_stop(struct hid_device *hid)
+{
+	hid->claimed = 0;
+}
+
+static int goodix_hid_open(struct hid_device *hid)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+
+	set_bit(GOODIX_HID_STARTED, &ts->flags);
+	return 0;
+}
+
+static void goodix_hid_close(struct hid_device *hid)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+
+	clear_bit(GOODIX_HID_STARTED, &ts->flags);
+}
+
+/* Return date length of response data */
+static int goodix_hid_check_ack_status(struct goodix_ts_data *ts)
+{
+	struct goodix_hid_report_header hdr;
+	int retry = 20;
+	int error;
+
+	while (retry--) {
+		/*
+		 * 3 bytes of hid request response data
+		 * - byte 0:    Ack flag, value of 1 for data ready
+		 * - bytes 1-2: Response data length
+		 */
+		error = goodix_spi_read(ts, ts->hid_report_addr,
+					&hdr, sizeof(hdr));
+		if (!error && (hdr.flag & GOODIX_HID_ACK_READY_FLAG))
+			return le16_to_cpu(hdr.size);
+
+		/* Wait 10ms for another try */
+		usleep_range(10000, 11000);
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * goodix_hid_get_raw_report() - Process hidraw GET REPORT operation
+ * @hid: hid device instance
+ * @reportnum: Report ID
+ * @buf: Buffer for store the report date
+ * @len: Length fo report data
+ * @report_type: Report type
+ *
+ * The function for hid_ll_driver.get_raw_report to handle the HIDRAW ioctl
+ * get report request. The transmitted data follows the standard i2c-hid
+ * protocol with a specified header.
+ *
+ * Return: The length of the data in the buf on success, negative error code
+ */
+static int goodix_hid_get_raw_report(struct hid_device *hid,
+				     unsigned char reportnum,
+				     u8 *buf, size_t len,
+				     unsigned char report_type)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+	u16 data_register = le16_to_cpu(ts->hid_desc.data_register);
+	u16 cmd_register = le16_to_cpu(ts->hid_desc.cmd_register);
+	u8 tmp_buf[GOODIX_HID_MAX_INBUF_SIZE];
+	int tx_len = 0, args_len = 0;
+	int response_data_len;
+	u8 args[3];
+	int error;
+
+	if (report_type == HID_OUTPUT_REPORT)
+		return -EINVAL;
+
+	if (reportnum == 3) {
+		/* Get win8 signature data */
+		error = goodix_spi_read(ts, GOODIX_HID_SIGN_ADDR, buf, len);
+		if (error) {
+			dev_err(ts->dev, "failed get win8 sign: %d", error);
+			return -EINVAL;
+		}
+		return len;
+	}
+
+	if (reportnum >= 0x0F)
+		args[args_len++] = reportnum;
+
+	put_unaligned_le16(data_register, args + args_len);
+	args_len += sizeof(data_register);
+
+	/* Clean 3 bytes of hid ack header data */
+	memset(tmp_buf, 0, GOODIX_HID_ACK_HEADER_SIZE);
+	tx_len += GOODIX_HID_ACK_HEADER_SIZE;
+
+	put_unaligned_le16(cmd_register, tmp_buf + tx_len);
+	tx_len += sizeof(cmd_register);
+
+	tmp_buf[tx_len] = (report_type == HID_FEATURE_REPORT ? 0x03 : 0x01) << 4;
+	tmp_buf[tx_len] |=  reportnum >= 0x0F ? 0x0F : reportnum;
+	tx_len++;
+
+	tmp_buf[tx_len++] = GOODIX_HID_GET_REPORT_CMD;
+
+	memcpy(tmp_buf + tx_len, args, args_len);
+	tx_len += args_len;
+
+	/* Step1: write report request info */
+	error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len);
+	if (error) {
+		dev_err(ts->dev, "failed send read feature cmd, %d", error);
+		return error;
+	}
+
+	/* No need read response data */
+	if (!len)
+		return 0;
+
+	/* Step2: check response data status */
+	response_data_len = goodix_hid_check_ack_status(ts);
+	if (response_data_len <= GOODIX_HID_PKG_LEN_SIZE)
+		return -EINVAL;
+
+	len = min(len, response_data_len - GOODIX_HID_PKG_LEN_SIZE);
+	/* Step3: read response data(skip 2bytes of hid pkg length) */
+	error = goodix_spi_read(ts, ts->hid_report_addr +
+				GOODIX_HID_ACK_HEADER_SIZE +
+				GOODIX_HID_PKG_LEN_SIZE, buf, len);
+	if (error) {
+		dev_err(ts->dev, "failed read hid response data, %d", error);
+		return error;
+	}
+
+	if (buf[0] != reportnum) {
+		dev_err(ts->dev, "incorrect report (%d vs %d expected)",
+			buf[0], reportnum);
+		return -EINVAL;
+	}
+	return len;
+}
+
+/**
+ * goodix_hid_set_raw_report() - process hidraw SET REPORT operation
+ * @hid: HID device
+ * @reportnum: Report ID
+ * @buf: Buffer for communication
+ * @len: Length of data in the buffer
+ * @report_type: Report type
+ *
+ * The function for hid_ll_driver.get_raw_report to handle the HIDRAW ioctl
+ * set report request. The transmitted data follows the standard i2c-hid
+ * protocol with a specified header.
+ *
+ * Return: The length of the data sent, negative error code on failure
+ */
+static int goodix_hid_set_raw_report(struct hid_device *hid,
+				     unsigned char reportnum,
+				     __u8 *buf, size_t len,
+				     unsigned char report_type)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+	u16 data_register = le16_to_cpu(ts->hid_desc.data_register);
+	u16 cmd_register = le16_to_cpu(ts->hid_desc.cmd_register);
+	int tx_len = 0, args_len = 0;
+	u8 tmp_buf[GOODIX_HID_MAX_INBUF_SIZE];
+	u8 args[5];
+	int error;
+
+	if (reportnum >= 0x0F) {
+		args[args_len++] = reportnum;
+		reportnum = 0x0F;
+	}
+
+	put_unaligned_le16(data_register, args + args_len);
+	args_len += sizeof(data_register);
+
+	put_unaligned_le16(GOODIX_HID_PKG_LEN_SIZE + len, args + args_len);
+	args_len += GOODIX_HID_PKG_LEN_SIZE;
+
+	/* Clean 3 bytes of hid ack header data */
+	memset(tmp_buf, 0, GOODIX_HID_ACK_HEADER_SIZE);
+	tx_len += GOODIX_HID_ACK_HEADER_SIZE;
+
+	put_unaligned_le16(cmd_register, tmp_buf + tx_len);
+	tx_len += sizeof(cmd_register);
+
+	tmp_buf[tx_len++] = ((report_type == HID_FEATURE_REPORT ? 0x03 : 0x02) << 4) | reportnum;
+	tmp_buf[tx_len++] = GOODIX_HID_SET_REPORT_CMD;
+
+	memcpy(tmp_buf + tx_len, args, args_len);
+	tx_len += args_len;
+
+	memcpy(tmp_buf + tx_len, buf, len);
+	tx_len += len;
+
+	error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len);
+	if (error) {
+		dev_err(ts->dev, "failed send report: %*ph", tx_len, tmp_buf);
+		return error;
+	}
+	return len;
+}
+
+static int goodix_hid_raw_request(struct hid_device *hid,
+				  unsigned char reportnum,
+				  __u8 *buf, size_t len,
+				  unsigned char rtype, int reqtype)
+{
+	struct goodix_ts_data *ts = hid->driver_data;
+	int error = -EINVAL;
+
+	guard(mutex)(&ts->hid_request_lock);
+	switch (reqtype) {
+	case HID_REQ_GET_REPORT:
+		error = goodix_hid_get_raw_report(hid, reportnum, buf,
+						  len, rtype);
+		break;
+	case HID_REQ_SET_REPORT:
+		if (buf[0] == reportnum)
+			error = goodix_hid_set_raw_report(hid, reportnum,
+							  buf, len, rtype);
+		break;
+	default:
+		break;
+	}
+
+	return error;
+}
+
+static struct hid_ll_driver goodix_hid_ll_driver = {
+	.parse = goodix_hid_parse,
+	.start = goodix_hid_start,
+	.stop = goodix_hid_stop,
+	.open = goodix_hid_open,
+	.close = goodix_hid_close,
+	.raw_request = goodix_hid_raw_request
+};
+
+static irqreturn_t goodix_hid_irq(int irq, void *data)
+{
+	struct goodix_ts_data *ts = data;
+	struct goodix_hid_report_event *event;
+	struct goodix_hid_report_package *pkg;
+	u16 report_size;
+
+	if (!test_bit(GOODIX_HID_STARTED, &ts->flags))
+		return IRQ_HANDLED;
+	/*
+	 * First, read buffer with space for header and coordinate package:
+	 * - event header = 3 bytes
+	 * - coordinate event = GOODIX_HID_COOR_PKG_LEN bytes
+	 *
+	 * If the data size info in the event header exceeds
+	 * GOODIX_HID_COOR_PKG_LEN, it means that there are other packages
+	 * besides the coordinate package.
+	 */
+	event = goodix_get_event_report(ts, ts->hid_report_addr, ts->event_buf,
+					GOODIX_HID_ACK_HEADER_SIZE +
+					GOODIX_HID_COOR_PKG_LEN);
+	if (!event) {
+		dev_err(ts->dev, "failed get coordinate data");
+		return IRQ_HANDLED;
+	}
+
+	/* Check coordinate data valid falg */
+	if (event->hdr.flag != GOODIX_HID_REPORT_READY_FLAG)
+		return IRQ_HANDLED;
+
+	pkg = (struct goodix_hid_report_package *)event->data;
+	if (le16_to_cpu(pkg->size) < GOODIX_HID_PKG_LEN_SIZE) {
+		dev_err(ts->dev, "invalid coordinate event package size, %d",
+			le16_to_cpu(pkg->size));
+		return IRQ_HANDLED;
+	}
+	hid_input_report(ts->hid, HID_INPUT_REPORT, pkg->data,
+			 le16_to_cpu(pkg->size) - GOODIX_HID_PKG_LEN_SIZE, 1);
+
+	report_size = le16_to_cpu(event->hdr.size);
+	/* Check if there are other packages */
+	if (report_size <= GOODIX_HID_COOR_PKG_LEN)
+		return IRQ_HANDLED;
+
+	if (report_size >= ts->hid_max_event_sz) {
+		dev_err(ts->dev, "package size exceed limit %d vs %d",
+			report_size, ts->hid_max_event_sz);
+		return IRQ_HANDLED;
+	}
+
+	/* Read the package behind the coordinate data */
+	pkg = goodix_get_event_report(ts, ts->hid_report_addr + sizeof(*event),
+				      ts->event_buf,
+				      report_size - GOODIX_HID_COOR_PKG_LEN);
+	if (!pkg) {
+		dev_err(ts->dev, "failed read attachment data content");
+		return IRQ_HANDLED;
+	}
+
+	hid_input_report(ts->hid, HID_INPUT_REPORT, pkg->data,
+			 le16_to_cpu(pkg->size) - GOODIX_HID_PKG_LEN_SIZE, 1);
+
+	return IRQ_HANDLED;
+}
+
+static int goodix_hid_init(struct goodix_ts_data *ts)
+{
+	struct hid_device *hid;
+	int error;
+
+	/* Get hid descriptor */
+	error = goodix_spi_read(ts, GOODIX_HID_DESC_ADDR, &ts->hid_desc,
+				sizeof(ts->hid_desc));
+	if (error) {
+		dev_err(ts->dev, "failed get hid desc, %d", error);
+		return error;
+	}
+
+	hid = hid_allocate_device();
+	if (IS_ERR(hid))
+		return PTR_ERR(hid);
+
+	hid->driver_data = ts;
+	hid->ll_driver = &goodix_hid_ll_driver;
+	hid->bus = BUS_SPI;
+	hid->dev.parent = &ts->spi->dev;
+
+	hid->version = le16_to_cpu(ts->hid_desc.bcd_version);
+	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",
+		 hid->vendor, hid->product);
+
+	error = hid_add_device(hid);
+	if (error) {
+		dev_err(ts->dev, "failed add hid device, %d", error);
+		hid_destroy_device(hid);
+		return error;
+	}
+
+	ts->hid = hid;
+	return 0;
+}
+
+static int goodix_spi_probe(struct spi_device *spi)
+{
+	struct device *dev = &spi->dev;
+	struct goodix_ts_data *ts;
+	int error;
+
+	/* init spi_device */
+	spi->mode            = SPI_MODE_0;
+	spi->bits_per_word   = 8;
+	error = spi_setup(spi);
+	if (error)
+		return error;
+
+	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	mutex_init(&ts->hid_request_lock);
+	spi_set_drvdata(spi, ts);
+	ts->spi = spi;
+	ts->dev = dev;
+	ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ts->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ts->reset_gpio),
+				     "failed to request reset gpio\n");
+
+	error = device_property_read_u32(dev, "goodix,hid-report-addr",
+					 &ts->hid_report_addr);
+	if (error)
+		return dev_err_probe(dev, error,
+				     "failed get hid report addr\n");
+
+	error = goodix_dev_confirm(ts);
+	if (error)
+		return error;
+
+	/* Waits 150ms for firmware to fully boot */
+	msleep(GOODIX_NORMAL_RESET_DELAY_MS);
+
+	error = goodix_hid_init(ts);
+	if (error) {
+		dev_err(dev, "failed init hid device");
+		return error;
+	}
+
+	error = devm_request_threaded_irq(&ts->spi->dev, ts->spi->irq,
+					  NULL, goodix_hid_irq, IRQF_ONESHOT,
+					  "goodix_spi_hid", ts);
+	if (error) {
+		dev_err(ts->dev, "could not register interrupt, irq = %d, %d",
+			ts->spi->irq, error);
+		goto err_destroy_hid;
+	}
+
+	return 0;
+
+err_destroy_hid:
+	hid_destroy_device(ts->hid);
+	return error;
+}
+
+static void goodix_spi_remove(struct spi_device *spi)
+{
+	struct goodix_ts_data *ts = spi_get_drvdata(spi);
+
+	disable_irq(spi->irq);
+	hid_destroy_device(ts->hid);
+	kfree(ts->event_buf);
+}
+
+static void goodix_spi_shutdown(struct spi_device *spi)
+{
+	struct goodix_ts_data *ts = spi_get_drvdata(spi);
+
+	disable_irq(spi->irq);
+	hid_destroy_device(ts->hid);
+}
+
+static int goodix_spi_set_power(struct goodix_ts_data *ts, int power_state)
+{
+	u8 power_control_cmd[] = {0x00, 0x00, 0x00, 0x87, 0x02, 0x00, 0x08};
+	int error;
+
+	/* value 0 for power on, 1 for power sleep */
+	power_control_cmd[5] = power_state;
+
+	guard(mutex)(&ts->hid_request_lock);
+	error = goodix_spi_write(ts, ts->hid_report_addr, power_control_cmd,
+				 sizeof(power_control_cmd));
+	if (error) {
+		dev_err(ts->dev, "failed set power mode: %s",
+			power_state == GOODIX_SPI_POWER_ON ? "on" : "sleep");
+		return error;
+	}
+	return 0;
+}
+
+static int goodix_spi_suspend(struct device *dev)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	int error;
+
+	error = goodix_spi_set_power(ts, GOODIX_SPI_POWER_SLEEP);
+	disable_irq(ts->spi->irq);
+	return error;
+}
+
+static int goodix_spi_resume(struct device *dev)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+	enable_irq(ts->spi->irq);
+
+	return goodix_spi_set_power(ts, GOODIX_SPI_POWER_ON);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(goodix_spi_pm_ops,
+				goodix_spi_suspend, goodix_spi_resume);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id goodix_spi_acpi_match[] = {
+	{ "GXTS7986" },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, goodix_spi_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id goodix_spi_of_match[] = {
+	{ .compatible = "goodix,gt7986u", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, goodix_spi_of_match);
+#endif
+
+static const struct spi_device_id goodix_spi_ids[] = {
+	{ "gt7986u" },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, goodix_spi_ids);
+
+static struct spi_driver goodix_spi_driver = {
+	.driver = {
+		.name = "goodix-spi-hid",
+		.acpi_match_table = ACPI_PTR(goodix_spi_acpi_match),
+		.of_match_table = of_match_ptr(goodix_spi_of_match),
+		.pm = pm_sleep_ptr(&goodix_spi_pm_ops),
+	},
+	.probe =	goodix_spi_probe,
+	.remove =	goodix_spi_remove,
+	.shutdown =	goodix_spi_shutdown,
+	.id_table =	goodix_spi_ids,
+};
+module_spi_driver(goodix_spi_driver);
+
+MODULE_DESCRIPTION("Goodix SPI driver for HID touchscreen");
+MODULE_AUTHOR("Goodix, Inc.");
+MODULE_LICENSE("GPL");
-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 0/2] HID: add initial support for Goodix HID-over-SPI touchscreen
From: Charles Wang @ 2024-06-18  8:44 UTC (permalink / raw)
  To: dmitry.torokhov, dan.carpenter, conor, robh
  Cc: dianders, krzk+dt, jikos, bentiss, hbarnor, linux-input,
	devicetree, linux-kernel, Charles Wang

This patch introduces a new driver to support the Goodix GT7986U
touch controller. This device is not compatible with Microsoft's
HID-over-SPI protocol and therefore needs to implement its own
flavor. The data reported is packaged according to the HID
protocol but uses SPI for communication to improve speed. This
enables the device to transmit not only coordinate data but also
corresponding raw data that can be accessed by user-space programs
through the hidraw interface. The raw data can be utilized for
functions like palm rejection, thereby improving the touch experience.

Key features:
- Device connection confirmation and initialization
- IRQ-based event reporting to the input subsystem
- Support for HIDRAW operations (GET_REPORT and SET_REPORT)

Signed-off-by: Charles Wang <charles.goodix@gmail.com>
---
Changes in v5:
- Add additional descriptive information to the dt-binding file.
- Fixed build warnings reported by kernel test robot.

Changes in v4:
- Allocate memory based on the report information.
- Added a new function goodix_get_event_report() to retrieve report data,
  reducing memory copy operations and avoiding the use of reg_rw_lock.
- Add low power control operations.
- Implemented power management operations.
- Introduced GOODIX_HID_STARTED to record the current device operating state.
- Add OF match table.

Changes in v3:
- Renamed the driver file to hid-goodix-spi.c.
- Mentioned in the commit message that this implementation is not compatible with
  Microsoft's HID-over-SPI protocol.
- Modified the driver to fetch the GOODIX_HID_REPORT_ADDR from device properties.
- Add a lock to prevent concurrent hid feature request operations.
- Optimized the SPI read/write functions by reducing the number of malloc calls.

Changes in v2:
- Fixed build warnings reported by kernel test robot

---
Charles Wang (2):
  HID: hid-goodix: Add Goodix HID-over-SPI driver
  dt-bindings: input: Goodix SPI HID Touchscreen

 .../bindings/input/goodix,gt7986u.yaml        |  72 ++
 drivers/hid/Kconfig                           |   6 +
 drivers/hid/Makefile                          |   1 +
 drivers/hid/hid-goodix-spi.c                  | 811 ++++++++++++++++++
 4 files changed, 890 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
 create mode 100644 drivers/hid/hid-goodix-spi.c

-- 
2.43.0


^ permalink raw reply

* Re: Xinput Controllers No Longer Working
From: Linux regression tracking (Thorsten Leemhuis) @ 2024-06-18  7:44 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Edward Wawrzynski, Linux regressions mailing list,
	open list:HID CORE LAYER, LKML
In-Reply-To: <CABRw72rifuVjs+LU5bB-2va11h=COyPpeBzWYkEMP+dW_h6MQQ@mail.gmail.com>

Hi, Thorsten here, the Linux kernel's regression tracker. Top-posting
for once, to make this easily accessible to everyone.

Dmitry, Edward seems to have some regression with Xinput Controllers no
Longer Working since v6.8..v6.9 and still not working with mainline. The
thread starts here:
https://lore.kernel.org/all/CABRw72orHLEqpAS%3DcW1ThGkVUW0juqc7Y_-N2%3Do-k0rSqgpLxA@mail.gmail.com/

Dmesg files are attached to the parent of this mail. I briefly looked
into them but no obvious problem jumped out to me untrained eyes.

Edward, with a bit of luck Dmitry might have an idea what's wrong here.
But if not you might need to perform a git bisection to find the change
that broke things:
https://docs.kernel.org/admin-guide/verify-bugs-and-bisect-regressions.html

That process would also rule out that some config change on the Fedora
side causes this.

Ciao, Thorsten

On 18.06.24 02:03, Edward Wawrzynski wrote:
> Hi Thorsten - I've removed the stable mailing list.
> 
> Sorry I took so long to respond. I just got the information you
> requested. To add onto the previous report, the kernel I booted into
> this time is 6.8.12, and the Xinput controllers still work perfectly.
> 
> I've attached two separate files I've generated, one on 6.9.4 (the
> broken one) and one on 6.8.12 (the working one). Please let me know if
> I can be of any further assistance.
> 
> On Mon, Jun 17, 2024 at 12:14 PM Linux regression tracking (Thorsten
> Leemhuis) <regressions@leemhuis.info> wrote:
>>
>> [to anyone that replies to this: please drop the stable mailing list
>> from CC, as this sounds like a mainline regressin]
>>
>> Hi Edward! Thx for your report
>>
>> On 17.06.24 17:37, Edward Wawrzynski wrote:
>>>
>>> I was reaching out to report that there's been a regression in the
>>> latest stable 6.9.4 kernel. I'm using Fedora 40 and 6.9.4 just got
>>> pushed to the repos recently. Upon updating, my wired USB Xinput
>>> controllers no longer get detected.
>>>
>>> I've tried two 8BitDo controllers, the one being the 8BitDo Pro 2
>>> Bluetooth (with a USB cable) and the other being the 8BitDo Pro 2
>>> Wired Controller for Xbox. Neither of them are being detected on
>>> Kernel 6.9.4, despite previously working throughout the lifetime of
>>> Fedora 40's 6.8.x kernel versions, the latest being 6.8.11. I've also
>>> tried the vanilla kernel, as well as the latest vanilla mainline
>>> kernel from Fedora's COPR: 6.10.0-0.rc4.337.vanilla.fc40.x86_64.
>>>
>>> To reproduce, simply load Kernel 6.9.4+
>>
>> That sounds a lot like it is a mainline regression that was introduced
>> between 6.8.y and 6.9;
>>
>>> and plug a USB controller in
>>> with XInput (either an Xbox controller or something else that emulates
>>> one). It won't be detected. I plugged in a PS5 controller and it
>>> worked, but when I plugged in an Xbox Series S controller, it didn't
>>> work. The 8BitDo Pro 2 Bluetooth controller has four different
>>> settings (Switch, Android, DirectInput, Xinput), and it was detected
>>> and worked on every setting except for the Xinput setting. Reverting
>>> to version 6.8.11 fixes the issues immediately.
>>
>> Could you please share the output of "journalctl --dmesg --output=short"
>> for both a working and a broken kernel?

--
Everything you wanna know about Linux kernel regression tracking:
https://linux-regtracking.leemhuis.info/about/#tldr
If I did something stupid, please tell me, as explained on that page.

P.S.: let me add this to the tracking:

#regzbot report /
#regzbot introduced v6.8..v6.9
#regzbot title input: Xinput Controllers No Longer Working
#regzbot ignore-activity

^ permalink raw reply

* Re: [PATCH v4 2/2] dt-bindings: input: Goodix SPI HID Touchscreen
From: Charles Wang @ 2024-06-18  7:27 UTC (permalink / raw)
  To: Conor Dooley
  Cc: dmitry.torokhov, dan.carpenter, dianders, robh, krzk+dt, jikos,
	bentiss, hbarnor, linux-input, devicetree, linux-kernel
In-Reply-To: <20240614-blah-sworn-1e13ec9c0e94@spud>

On Fri, Jun 14, 2024 at 04:27:52PM +0100, Conor Dooley wrote:
> On Fri, Jun 14, 2024 at 08:15:38PM +0800, Charles Wang wrote:
> > The Goodix GT7986U touch controller report touch data according to the
> > HID protocol through the SPI bus. However, it is incompatible with
> > Microsoft's HID-over-SPI protocol.
> 
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - goodix,gt7986u
> 
> > +  goodix,hid-report-addr:
> > +    description: the register address for retrieving HID report data.
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> 
> You're also missing an explanation anywhere in the patch for why this
> address varies between gt7986u devices.

Ack, I will add an explanation in the next commit.

The address variation between GT7986U devices is related to their firmware
versions. While we strive to maintain consistency, significant firmware
upgrades might necessitate changes to this address.

Charles

Thanks

^ permalink raw reply

* Re: [PATCH v4 2/2] dt-bindings: input: Goodix SPI HID Touchscreen
From: Charles Wang @ 2024-06-18  7:15 UTC (permalink / raw)
  To: Conor Dooley
  Cc: dmitry.torokhov, dan.carpenter, dianders, robh, krzk+dt, jikos,
	bentiss, hbarnor, linux-input, devicetree, linux-kernel
In-Reply-To: <20240614-renewably-snowless-861ca2ab9c93@spud>

On Fri, Jun 14, 2024 at 04:26:22PM +0100, Conor Dooley wrote:
> On Fri, Jun 14, 2024 at 08:15:38PM +0800, Charles Wang wrote:
> > The Goodix GT7986U touch controller report touch data according to the
> > HID protocol through the SPI bus. However, it is incompatible with
> > Microsoft's HID-over-SPI protocol.
> > 
> > Signed-off-by: Charles Wang <charles.goodix@gmail.com>
> > ---
> >  .../bindings/input/goodix,gt7986u.yaml        | 65 +++++++++++++++++++
> >  1 file changed, 65 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml b/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
> > new file mode 100644
> > index 000000000..1c518d03b
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/goodix,gt7986u.yaml
> > @@ -0,0 +1,65 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/input/goodix,gt7986u.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: GOODIX GT7986U SPI HID Touchscreen
> > +
> > +maintainers:
> > +  - Charles Wang <charles.goodix@gmail.com>
> > +
> > +description:
> > +  Supports the Goodix GT7986U touchscreen.
> > +  This touch controller reports data packaged according to the HID protocol,
> > +  but is incompatible with Microsoft's HID-over-SPI protocol.
> > +
> > +allOf:
> > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - goodix,gt7986u
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  reset-gpios:
> > +    maxItems: 1
> > +    description: reset gpio the chip is connected to.
> > +
> > +  goodix,hid-report-addr:
> > +    description: the register address for retrieving HID report data.
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +
> > +additionalProperties: false
> 
> unevaluatedProperties: false.
> 
> Please test your binding w/ dt_binding_check.
> 

Ack. I have tested it using "make dt_binding_check" and there were no errors
or warnings output. :(

Additionally, I have already run "pip3 install dtschema --upgrade". 

> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - goodix,hid-report-addr
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    #include <dt-bindings/gpio/gpio.h>
> > +    spi {
> > +      #address-cells = <1>;
> > +      #size-cells = <0>;
> > +      num-cs = <1>;
> > +      cs-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
> 
> cs-gpios shouldn't be needed for a basic example.
> 
> Blank line here before the child node please.
> 
Ack

Charles

Thanks


^ permalink raw reply

* Re: [PATCH v1 2/2] Input: Add driver for PixArt PS/2 touchpad
From: Binbin Zhou @ 2024-06-18  2:28 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Binbin Zhou, Huacai Chen, Huacai Chen, loongson-kernel,
	linux-input, Xiaotian Wu, Jon Xie, Jay Lee
In-Reply-To: <Zk5OXnPT64AkEftJ@google.com>

Hi Dmitry:

Sorry for the late reply and thanks for your detailed review.

On Thu, May 23, 2024 at 1:58 AM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> Hi Binbin,
>
> On Wed, May 15, 2024 at 04:58:57PM +0800, Binbin Zhou wrote:
> > This patch introduces a driver for the PixArt PS/2 touchpad, which
> > supports both clickpad and touchpad types.
> >
> > Co-developed-by: Jon Xie <jon_xie@pixart.com>
> > Signed-off-by: Jon Xie <jon_xie@pixart.com>
> > Co-developed-by: Jay Lee <jay_lee@pixart.com>
> > Signed-off-by: Jay Lee <jay_lee@pixart.com>
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >  drivers/input/mouse/Kconfig        |  12 ++
> >  drivers/input/mouse/Makefile       |   1 +
> >  drivers/input/mouse/pixart_ps2.c   | 294 +++++++++++++++++++++++++++++
> >  drivers/input/mouse/pixart_ps2.h   |  31 +++
> >  drivers/input/mouse/psmouse-base.c |  17 ++
> >  drivers/input/mouse/psmouse.h      |   1 +
> >  6 files changed, 356 insertions(+)
> >  create mode 100644 drivers/input/mouse/pixart_ps2.c
> >  create mode 100644 drivers/input/mouse/pixart_ps2.h
> >
> > diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
> > index 833b643f0616..8a27a20d04b0 100644
> > --- a/drivers/input/mouse/Kconfig
> > +++ b/drivers/input/mouse/Kconfig
> > @@ -69,6 +69,18 @@ config MOUSE_PS2_LOGIPS2PP
> >
> >         If unsure, say Y.
> >
> > +config MOUSE_PS2_PIXART
> > +     bool "PixArt PS/2 touchpad protocol extension" if EXPERT
> > +     default y
> > +     depends on MOUSE_PS2
> > +     help
> > +       This driver supports the PixArt PS/2 touchpad found in some
> > +       laptops.
> > +       Say Y here if you have a PixArt PS/2 TouchPad connected to
> > +       your system.
> > +
> > +       If unsure, say Y.
> > +
> >  config MOUSE_PS2_SYNAPTICS
> >       bool "Synaptics PS/2 mouse protocol extension" if EXPERT
> >       default y
> > diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> > index a1336d5bee6f..563029551529 100644
> > --- a/drivers/input/mouse/Makefile
> > +++ b/drivers/input/mouse/Makefile
> > @@ -32,6 +32,7 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH)        += elantech.o
> >  psmouse-$(CONFIG_MOUSE_PS2_OLPC)     += hgpk.o
> >  psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP)        += logips2pp.o
> >  psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
> > +psmouse-$(CONFIG_MOUSE_PS2_PIXART)   += pixart_ps2.o
> >  psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
> >  psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)       += trackpoint.o
> >  psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
> > diff --git a/drivers/input/mouse/pixart_ps2.c b/drivers/input/mouse/pixart_ps2.c
> > new file mode 100644
> > index 000000000000..532d84ab7654
> > --- /dev/null
> > +++ b/drivers/input/mouse/pixart_ps2.c
> > @@ -0,0 +1,294 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Pixart Touchpad Controller 1336U PS2 driver
> > + *
> > + * Author: Jon Xie <jon_xie@pixart.com>
> > + *         Jay Lee <jay_lee@pixart.com>
> > + * Further cleanup and restructuring by:
> > + *         Binbin Zhou <zhoubinbin@loongson.cn>
> > + *
> > + * Copyright (C) 2021-2024 Pixart Imaging
> > + * Copyright (C) 2024 Loongson Technology Corporation Limited.
> > + *
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/libps2.h>
> > +#include <linux/input/mt.h>
> > +#include <linux/serio.h>
> > +#include <linux/slab.h>
> > +#include "pixart_ps2.h"
> > +
> > +static int pixart_mode_detect(struct psmouse *psmouse)
> > +{
> > +     u8 param[1];
> > +
> > +     if (ps2_command(&psmouse->ps2dev, param, PIXART_CMD_REPORT_FORMAT))
> > +             return -EIO;
> > +
> > +     return (param[0] == 1) ? PIXART_MODE_ABS : PIXART_MODE_REL;
> > +}
> > +
> > +static int pixart_type_detect(struct psmouse *psmouse)
> > +{
> > +     struct ps2dev *ps2dev = &psmouse->ps2dev;
> > +     u8 param[3];
>
> You are not initializing this.
>
> > +
> > +     param[0] = 0x0a;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
> > +     param[0] = 0x0;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> > +     param[0] = 0x0;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> > +     param[0] = 0x0;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> > +     param[0] = 0x03;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
> > +
>
> So here you might be comparing with random garbage.
>
> I think it would be better if "param" was initialized and at least the
> return value of the last ps2_command() checked to make sure the device
> ACKed it and returned proper amount of data.

OK, I will do it and check for all uninitialized variables.
I see that other drivers basically check every ps2_command(). I need
to do something similar, which will be more rigorous.
>
> > +     return (param[0] == 0x0e) ? PIXART_TYPE_TOUCHPAD : PIXART_TYPE_CLICKPAD;
> > +}
> > +
> > +static int pixart_intellimouse_detect(struct psmouse *psmouse)
> > +{
> > +     struct ps2dev *ps2dev = &psmouse->ps2dev;
> > +     u8 param[2];
> > +
> > +     param[0] = 200;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
> > +     param[0] = 100;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
> > +     param[0] = 80;
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
> > +     ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
> > +
> > +     return (param[0] == 3) ? 0 : -1;
> > +}
> > +
> > +static void pixart_reset(struct psmouse *psmouse)
> > +{
> > +     ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
> > +     msleep(100);
> > +     psmouse_reset(psmouse);
> > +}
> > +
> > +static psmouse_ret_t pixart_process_abs_packet(struct psmouse *psmouse)
> > +{
> > +     struct pixart_data *priv = psmouse->private;
> > +     struct input_dev *dev = psmouse->dev;
> > +     u8 *packet = psmouse->packet;
> > +     u8 contact_cnt = (packet[0] >> 4) & 0x07;
> > +     unsigned int abs_x, abs_y;
> > +     int i, id, fingers = 0;
> > +     bool tip;
> > +
> > +     if (contact_cnt > MAX_FINGERS || ((packet[0] & 0x8c) != 0x80))
> > +             return PSMOUSE_BAD_DATA;
> > +
> > +     if (contact_cnt == MAX_FINGERS && psmouse->pktcnt < psmouse->pktsize)
> > +             return PSMOUSE_GOOD_DATA;
> > +     else if (contact_cnt == 0 && psmouse->pktcnt < 5)
> > +             return PSMOUSE_GOOD_DATA;
> > +     else if (psmouse->pktcnt < (3 * contact_cnt + 2))
> > +             return PSMOUSE_GOOD_DATA;
> > +
> > +     for (i = 0; i < contact_cnt; i++) {
> > +             id = packet[3 * i + 3] & 0x07;
> > +             abs_y = ((packet[3 * i + 3] & 0x30) << 4) | packet[3 * i + 1];
> > +             abs_x = ((packet[3 * i + 3] & 0xc0) << 2) | packet[3 * i + 2];
> > +
> > +             if (i == MAX_FINGERS - 1)
> > +                     tip = packet[14] & (0x01 << 1);
>
> Please use BIT().

OK..
>
> > +             else
> > +                     tip = packet[3 * contact_cnt + 1] & (0x01 << (2 * i + 1));
> > +
> > +             input_mt_slot(dev, id);
> > +             input_mt_report_slot_state(dev, MT_TOOL_FINGER, tip);
> > +             if (tip) {
>
>                 if (input_mt_report_slot_state(dev, MT_TOOL_FINGER, tip)) {
>

OK..
> > +                     fingers++;
> > +                     input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
> > +                     input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
> > +             }
> > +     }
> > +
> > +     input_mt_drop_unused(dev);
>
> Could you explain the protocol please? Does the device produce "lift
> off" packets for contacts? Why do you need to call
> input_mt_drop_unused() explicitly?
>
> > +     input_mt_report_pointer_emulation(dev, false);
> > +     input_mt_report_finger_count(dev, fingers);
> > +
> > +     if (priv->type == PIXART_TYPE_CLICKPAD) {
> > +             input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
> > +     } else {z
> > +             input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
> > +             input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
> > +     }
> > +
> > +     input_mt_report_pointer_emulation(dev, true);
>
> Why the 2 calls to input_mt_report_pointer_emulation()?
>
> > +     input_sync(dev);
> > +
> > +     return PSMOUSE_FULL_PACKET;
> > +}
> > +
> > +static psmouse_ret_t pixart_process_rel_packet(struct psmouse *psmouse)
> > +{
> > +     struct input_dev *dev = psmouse->dev;
> > +     u8 *packet = psmouse->packet;
> > +     int x = packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0;
> > +     int y = packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0;
> > +     int w = -(s8)packet[3];
> > +
> > +     if (psmouse->pktcnt < psmouse->pktsize)
> > +             return PSMOUSE_GOOD_DATA;
> > +
> > +     psmouse_report_standard_buttons(dev, packet[0]);
> > +     input_report_rel(dev, REL_X, x);
> > +     input_report_rel(dev, REL_Y, y);
> > +     input_report_rel(dev, REL_WHEEL, w);
> > +     input_sync(dev);
> > +
> > +     return PSMOUSE_FULL_PACKET;
> > +}
> > +
> > +static void pixart_disconnect(struct psmouse *psmouse)
> > +{
> > +     psmouse_info(psmouse, "Device disconnect");
>
> Please remove, no need to be noisy.

OK, I will drop it.
>
> > +     pixart_reset(psmouse);
> > +     kfree(psmouse->private);
> > +     psmouse->private = NULL;
> > +}
> > +
> > +static int pixart_reconnect(struct psmouse *psmouse)
> > +{
> > +     struct pixart_data *priv = psmouse->private;
> > +
> > +     psmouse_info(psmouse, "Device reconnect");
> > +     pixart_reset(psmouse);
> > +
> > +     priv->mode = pixart_mode_detect(psmouse);
> > +     if (priv->mode < 0) {
> > +             psmouse_err(psmouse, "Unable to detect the PixArt device");
> > +             return -EIO;
> > +     }
> > +
> > +     if (priv->mode == PIXART_MODE_ABS)
> > +             ps2_command(&psmouse->ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
> > +
> > +     return 0;
> > +}
> > +
> > +static void pixart_set_abs_input_params(struct input_dev *dev, struct pixart_data *priv)
> > +{
> > +     __clear_bit(EV_REL, dev->evbit);
> > +     __clear_bit(REL_X, dev->relbit);
> > +     __clear_bit(REL_Y, dev->relbit);
> > +     __clear_bit(BTN_MIDDLE, dev->keybit);
> > +
> > +     __set_bit(EV_KEY, dev->evbit);
> > +     __set_bit(BTN_LEFT, dev->keybit);
> > +     __set_bit(BTN_RIGHT, dev->keybit);
> > +     if (priv->type == PIXART_TYPE_CLICKPAD) {
> > +             __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
> > +             __clear_bit(BTN_RIGHT, dev->keybit);
> > +     }
> > +     __set_bit(BTN_TOUCH, dev->keybit);
> > +     __set_bit(BTN_TOOL_FINGER, dev->keybit);
> > +     __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
> > +     __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
> > +     __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
> > +     __set_bit(INPUT_PROP_POINTER, dev->propbit);
> > +
> > +     __set_bit(EV_ABS, dev->evbit);
> > +     input_set_abs_params(dev, ABS_X, 0, ABS_MAX_X, 0, 0);
> > +     input_set_abs_params(dev, ABS_Y, 0, ABS_MAX_Y, 0, 0);
> > +
> > +     input_set_abs_params(dev, ABS_MT_POSITION_X, 0, ABS_MAX_X, 0, 0);
> > +     input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, ABS_MAX_Y, 0, 0);
> > +
> > +     input_mt_init_slots(dev, SLOTS_NUMBER, 0);
> > +}
> > +
> > +static void pixart_set_rel_input_params(struct input_dev *dev, struct pixart_data *priv)
> > +{
> > +     __set_bit(EV_KEY, dev->evbit);
> > +     __set_bit(EV_REL, dev->evbit);
> > +     __set_bit(BTN_LEFT, dev->keybit);
> > +     __set_bit(BTN_RIGHT, dev->keybit);
> > +     __set_bit(REL_X, dev->relbit);
> > +     __set_bit(REL_Y, dev->relbit);
> > +     __set_bit(REL_WHEEL, dev->relbit);
> > +     __set_bit(INPUT_PROP_POINTER, dev->propbit);
> > +}
> > +
> > +int pixart_detect(struct psmouse *psmouse, bool set_properties)
> > +{
> > +     int mode, type;
> > +
> > +     pixart_reset(psmouse);
> > +
> > +     type = pixart_type_detect(psmouse);
>
> This returns PIXART_TYPE_TOUCHPAD or PIXART_TYPE_CLICKPAD, and never
> negative value.
>

I will try to check the ps2_command() return value in the
pixart_type_detect() and pixart_mode_detect(), so I think the check
here is still necessary.
> > +     if (type < 0)
> > +             return -ENODEV;
> > +
> > +     mode = pixart_mode_detect(psmouse);
>
> This relies on non-PixArt devices NAKing PIXART_CMD_REPORT_FORMAT
> command. What other touchpad/mice have you tested this on to make sure
> it does not mis-detect them?
>
> > +     if (mode < 0)
> > +             return -ENODEV;
> > +
> > +     psmouse_info(psmouse, "Detect PixArt Device.");
>
> No need to be this noisy.

OK, I will drop it.
>
> > +     if (set_properties) {
> > +             psmouse->vendor = "PixArt";
> > +             psmouse->name = (type == PIXART_TYPE_TOUCHPAD) ?
> > +                             "touchpad" : "clickpad";
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +int pixart_init(struct psmouse *psmouse)
> > +{
> > +     struct pixart_data *priv;
> > +
> > +     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     psmouse->private = priv;
> > +     pixart_reset(psmouse);
> > +
> > +     priv->type = pixart_type_detect(psmouse);
> > +     if (priv->type < 0)
> > +             goto fail;
> > +
> > +     priv->mode = pixart_mode_detect(psmouse);
> > +     if (priv->mode < 0) {
> > +             psmouse_err(psmouse, "Unable to initialize the PixArt device\n");
> > +             goto fail;
> > +     }
> > +
> > +     if (priv->mode == PIXART_MODE_ABS) {
> > +             ps2_command(&psmouse->ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
> > +             pixart_set_abs_input_params(psmouse->dev, priv);
> > +             psmouse->protocol_handler = pixart_process_abs_packet;
> > +             psmouse->pktsize = 15;
> > +     } else {
> > +             pixart_reset(psmouse);
> > +             pixart_intellimouse_detect(psmouse);
> > +             pixart_set_rel_input_params(psmouse->dev, priv);
> > +             psmouse->protocol_handler = pixart_process_rel_packet;
> > +             psmouse->pktsize = 4;
>
> Do we really need to handle this case? If the touchpad does not support
> absolute packets can we fail the detection and simply rely on the normal
> intellimouse detection and packet handling?
>

After some tests, the normal detection is well in PixArt, and I will
drop this case.

Thanks.
Binbin
> > +     }
> > +
> > +     psmouse->disconnect = pixart_disconnect;
> > +     psmouse->reconnect = pixart_reconnect;
> > +     psmouse->cleanup = pixart_reset;
> > +     /* resync is not supported yet */
> > +     psmouse->resync_time = 0;
> > +
> > +     psmouse_info(psmouse, "Set device as Type: %x, mode: %x", priv->type, priv->mode);
> > +     return 0;
> > +
> > +fail:
> > +     pixart_reset(psmouse);
> > +     kfree(priv);
> > +     psmouse->private = NULL;
> > +     return -1;
> > +}
> > diff --git a/drivers/input/mouse/pixart_ps2.h b/drivers/input/mouse/pixart_ps2.h
> > new file mode 100644
> > index 000000000000..224ab3a4f739
> > --- /dev/null
> > +++ b/drivers/input/mouse/pixart_ps2.h
> > @@ -0,0 +1,31 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#ifndef _PIXART_PS2_H
> > +#define _PIXART_PS2_H
> > +
> > +#include "psmouse.h"
> > +
> > +#define ABS_MAX_X    1023
> > +#define ABS_MAX_Y    579
> > +#define MAX_FINGERS  4
> > +#define SLOTS_NUMBER MAX_FINGERS
> > +
> > +#define PIXART_CMD_REPORT_FORMAT     0x01d8
> > +#define PIXART_CMD_SWITCH_PROTO              0x00de
> > +
> > +#define PIXART_MODE_REL      0
> > +#define PIXART_MODE_ABS      1
> > +
> > +#define PIXART_TYPE_CLICKPAD 0
> > +#define PIXART_TYPE_TOUCHPAD 1
> > +
> > +struct pixart_data {
> > +     int mode;
> > +     int type;
> > +     int x_max;
> > +     int y_max;
> > +};
> > +
> > +int pixart_detect(struct psmouse *psmouse, bool set_properties);
> > +int pixart_init(struct psmouse *psmouse);
> > +
> > +#endif  /* _PIXART_PS2_H */
> > diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
> > index a0aac76b1e41..41af3460077d 100644
> > --- a/drivers/input/mouse/psmouse-base.c
> > +++ b/drivers/input/mouse/psmouse-base.c
> > @@ -36,6 +36,7 @@
> >  #include "focaltech.h"
> >  #include "vmmouse.h"
> >  #include "byd.h"
> > +#include "pixart_ps2.h"
> >
> >  #define DRIVER_DESC  "PS/2 mouse driver"
> >
> > @@ -905,6 +906,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
> >               .detect         = byd_detect,
> >               .init           = byd_init,
> >       },
> > +#endif
> > +#ifdef CONFIG_MOUSE_PS2_PIXART
> > +     {
> > +             .type           = PSMOUSE_PIXART,
> > +             .name           = "PixArtPS/2",
> > +             .alias          = "pixart",
> > +             .detect         = pixart_detect,
> > +             .init           = pixart_init,
> > +     },
> >  #endif
> >       {
> >               .type           = PSMOUSE_AUTO,
> > @@ -1172,6 +1182,13 @@ static int psmouse_extensions(struct psmouse *psmouse,
> >                       return ret;
> >       }
> >
> > +     /* Try PixArt touchpad */
> > +     if (max_proto > PSMOUSE_IMEX &&
> > +         psmouse_try_protocol(psmouse, PSMOUSE_PIXART, &max_proto,
> > +                              set_properties, true)) {
> > +             return PSMOUSE_PIXART;
> > +     }
> > +
> >       if (max_proto > PSMOUSE_IMEX) {
> >               if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
> >                                        &max_proto, set_properties, true))
> > diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
> > index b05c6fbae7e3..23f7fa7243cb 100644
> > --- a/drivers/input/mouse/psmouse.h
> > +++ b/drivers/input/mouse/psmouse.h
> > @@ -69,6 +69,7 @@ enum psmouse_type {
> >       PSMOUSE_BYD,
> >       PSMOUSE_SYNAPTICS_SMBUS,
> >       PSMOUSE_ELANTECH_SMBUS,
> > +     PSMOUSE_PIXART,
> >       PSMOUSE_AUTO            /* This one should always be last */
> >  };
> >
> > --
> > 2.43.0
> >
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply

* Re: [PATCH v1 1/2] Input: psmouse - Expanding the psmouse packet array
From: Binbin Zhou @ 2024-06-18  2:27 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Binbin Zhou, Huacai Chen, Huacai Chen, loongson-kernel,
	linux-input, Xiaotian Wu
In-Reply-To: <Zk5HvUtMyWU1dssO@google.com>

On Thu, May 23, 2024 at 1:30 AM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> Hi Binbin,
>
> On Wed, May 15, 2024 at 04:58:56PM +0800, Binbin Zhou wrote:
> > According to the current design of PixArt touchpad hardware and FW, our
> > single packet data width needs 11 bytes/15 bytes to receive the complete
> > three-finger/four-finger data in absolute coordinate mode.
> > Obviously, it exceeds the design of the native driver, and we try to
> > extend the length of a single data packet to 16.
>
> Please fold this into the patch adding PixArt protocol support. There is
> no need to make this a separate patch.

Hi Dmitry:

Sorry for the late reply.
I will do it in my V2 patchset.

Thanks.
Binbin
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply

* Re: [PATCH v1] hid-playstation: DS4: Update rumble and lightbar together
From: Roderick Colenbrander @ 2024-06-17 23:01 UTC (permalink / raw)
  To: Max Staudt
  Cc: Roderick Colenbrander, Jiri Kosina, Benjamin Tissoires,
	linux-input, linux-kernel
In-Reply-To: <20240616163055.75174-1-max@enpas.org>

Hi Max,

Thanks for your patch. I'm a little hesitant to make changes here. The
console itself does the updates similar to this, though there are
different userspace kind of ways there to send things (so some paths
may kind of do what you saw). These flags are often used also to
enable other features in the output report (e.g. audio settings or
many others).

This driver is used in a lot of devices. Different vendors ranging
e.g. car manufacturers, phones, TVs,.. have their own unit /
regression tests suites to test integration. Where they send FF rumble
for example and check the bits in the output reports

We went through a lot of pain with many of such vendors (and are still
going through some). I would rather not shake things up for such a
narrow use cases for non-official devices.

Thanks,
Roderick

On Sun, Jun 16, 2024 at 9:40 AM Max Staudt <max@enpas.org> wrote:
>
> Some 3rd party gamepads expect updates to rumble and lightbar together,
> and setting one may cancel the other.
>
> This patch maximises compatibility by always sending rumble and lightbar
> updates whenever updates are sent to the gamepad: valid_flag0 is always
> >= 0x03.
>
> Further background reading:
>
> - Apparently the PS4 always sends rumble and lightbar updates together:
>
>   https://eleccelerator.com/wiki/index.php?title=DualShock_4#0x11_2
>
> - 3rd party gamepads may not implement lightbar_blink, and may simply
>   ignore updates with 0x07 set, according to:
>
>   https://github.com/Ryochan7/DS4Windows/pull/1839
>
> This patch leaves the lightbar blink feature as-is: Likely, most users
> are unaware that it exists, hence it's unlikely that a packet with
> 0x07 set will even be sent in practice. Let's leave the function there,
> so users of first-party gamepads can continue to use it.
> ---
>  drivers/hid/hid-playstation.c | 55 ++++++++++++++++++++---------------
>  1 file changed, 31 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
> index e7c309cfe3a0..986a4ca8b664 100644
> --- a/drivers/hid/hid-playstation.c
> +++ b/drivers/hid/hid-playstation.c
> @@ -387,12 +387,10 @@ struct dualshock4 {
>         bool update_bt_poll_interval;
>         uint8_t bt_poll_interval;
>
> -       bool update_rumble;
>         uint8_t motor_left;
>         uint8_t motor_right;
>
>         /* Lightbar leds */
> -       bool update_lightbar;
>         bool update_lightbar_blink;
>         bool lightbar_enabled; /* For use by global LED control. */
>         uint8_t lightbar_red;
> @@ -2092,8 +2090,6 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig
>                 }
>         }
>
> -       ds4->update_lightbar = true;
> -
>         spin_unlock_irqrestore(&ds4->base.lock, flags);
>
>         dualshock4_schedule_work(ds4);
> @@ -2143,26 +2139,39 @@ static void dualshock4_output_worker(struct work_struct *work)
>
>         spin_lock_irqsave(&ds4->base.lock, flags);
>
> -       if (ds4->update_rumble) {
> -               /* Select classic rumble style haptics and enable it. */
> -               common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR;
> -               common->motor_left = ds4->motor_left;
> -               common->motor_right = ds4->motor_right;
> -               ds4->update_rumble = false;
> -       }
> +       /*
> +        * PS4 seems to send 0xf3 updates by default, according to a HCI trace:
> +        *   https://eleccelerator.com/wiki/index.php?title=DualShock_4#0x11_2
> +        *
> +        * This seems to be a very compatible value with third-party pads:
> +        *   https://github.com/Ryochan7/DS4Windows/pull/1839
> +        *
> +        * However, hid-playstation in v6.10 does not set the upper nibble,
> +        * and neither does hid-sony in v6.2, or BlueRetro. We should stick
> +        * to that for now, to minimise the chance of unexpected changes.
> +        *
> +        * So let's always update rumble and lightbar at the same time, with
> +        * the upper nibble cleared, resulting in valid_flag0 == 0x03.
> +        * Hopefully this will maximise compatibility with third-party pads.
> +        */
> +       common->valid_flag0 = DS4_OUTPUT_VALID_FLAG0_MOTOR |
> +                             DS4_OUTPUT_VALID_FLAG0_LED;
>
> -       if (ds4->update_lightbar) {
> -               common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED;
> -               /* Comptabile behavior with hid-sony, which used a dummy global LED to
> -                * allow enabling/disabling the lightbar. The global LED maps to
> -                * lightbar_enabled.
> -                */
> -               common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0;
> -               common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0;
> -               common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0;
> -               ds4->update_lightbar = false;
> -       }
> +       common->motor_left = ds4->motor_left;
> +       common->motor_right = ds4->motor_right;
> +
> +       /* Compatible behavior with hid-sony, which used a dummy global LED to
> +        * allow enabling/disabling the lightbar. The global LED maps to
> +        * lightbar_enabled.
> +        */
> +       common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0;
> +       common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0;
> +       common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0;
>
> +       /*
> +        * Output reports updating lightbar_blink will simply be ignored
> +        * by incompatible controllers, since valid_flag0 == 0x07.
> +        */
>         if (ds4->update_lightbar_blink) {
>                 common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK;
>                 common->lightbar_blink_on = ds4->lightbar_blink_on;
> @@ -2459,7 +2468,6 @@ static int dualshock4_play_effect(struct input_dev *dev, void *data, struct ff_e
>                 return 0;
>
>         spin_lock_irqsave(&ds4->base.lock, flags);
> -       ds4->update_rumble = true;
>         ds4->motor_left = effect->u.rumble.strong_magnitude / 256;
>         ds4->motor_right = effect->u.rumble.weak_magnitude / 256;
>         spin_unlock_irqrestore(&ds4->base.lock, flags);
> @@ -2520,7 +2528,6 @@ static void dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4)
>         ds4->lightbar_green = player_colors[player_id][1];
>         ds4->lightbar_blue = player_colors[player_id][2];
>
> -       ds4->update_lightbar = true;
>         dualshock4_schedule_work(ds4);
>  }
>
> --
> 2.39.2
>
>

^ permalink raw reply

* [PATCH] Input: qt1050 - handle CHIP_ID reading error
From: Andrei Lalaev @ 2024-06-17 18:30 UTC (permalink / raw)
  To: dmitry.torokhov, robh, m.felsch
  Cc: andrey.lalaev, linux-input, linux-kernel, Andrei Lalaev

From: Andrei Lalaev <andrei.lalaev@anton-paar.com>

If the device is missing, we get the following error:

  qt1050 3-0041: ID -1340767592 not supported

Let's handle this situation and print more informative error
when reading of CHIP_ID fails:

  qt1050 3-0041: Failed to read chip ID: -6

Fixes: cbebf5addec1 ("Input: qt1050 - add Microchip AT42QT1050 support")
Signed-off-by: Andrei Lalaev <andrei.lalaev@anton-paar.com>
---
 drivers/input/keyboard/qt1050.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c
index b51dfcd76038..056e9bc26026 100644
--- a/drivers/input/keyboard/qt1050.c
+++ b/drivers/input/keyboard/qt1050.c
@@ -226,7 +226,12 @@ static bool qt1050_identify(struct qt1050_priv *ts)
 	int err;
 
 	/* Read Chip ID */
-	regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+	err = regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+	if (err) {
+		dev_err(&ts->client->dev, "Failed to read chip ID: %d\n", err);
+		return false;
+	}
+
 	if (val != QT1050_CHIP_ID_VER) {
 		dev_err(&ts->client->dev, "ID %d not supported\n", val);
 		return false;
-- 
2.35.2


^ permalink raw reply related

* linux-next: build failure after merge of the bpf-next tree
From: Mark Brown @ 2024-06-17 18:15 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko, bpf,
	Networking, Benjamin Tissoires, Jiri Kosina
  Cc: Kui-Feng Lee, Martin KaFai Lau, linux-input,
	Linux Kernel Mailing List, Linux Next Mailing List, bpf

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

Hi all,

After merging the bpf-next tree, today's linux-next build (x86_64
allmodconfig) failed like this:

/tmp/next/build/drivers/hid/bpf/hid_bpf_struct_ops.c:280:16: error: initialization of 'int (*)(void *, struct bpf_link *)' from incompatible pointer type 'int (*)(void *)' [-Werror=incompatible-pointer-types]
  280 |         .reg = hid_bpf_reg,
      |                ^~~~~~~~~~~
/tmp/next/build/drivers/hid/bpf/hid_bpf_struct_ops.c:280:16: note: (near initialization for 'bpf_hid_bpf_ops.reg')
/tmp/next/build/drivers/hid/bpf/hid_bpf_struct_ops.c:281:18: error: initialization of 'void (*)(void *, struct bpf_link *)' from incompatible pointer type 'void (*)(void *)' [-Werror=incompatible-pointer-types]
  281 |         .unreg = hid_bpf_unreg,
      |                  ^~~~~~~~~~~~~
/tmp/next/build/drivers/hid/bpf/hid_bpf_struct_ops.c:281:18: note: (near initialization for 'bpf_hid_bpf_ops.unreg')

Caused by commit

  73287fe228721b ("bpf: pass bpf_struct_ops_link to callbacks in bpf_struct_ops.")

interacting with commit

  ebc0d8093e8c97 ("HID: bpf: implement HID-BPF through bpf_struct_ops")

from the HID tree.

I've fixed it up as below:

From e8aeaba00440845f9bd8d6183ca5d7383a678cd3 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@kernel.org>
Date: Mon, 17 Jun 2024 19:02:27 +0100
Subject: [PATCH] HID: bpf: Fix up build

Fix up build error due to 73287fe228721b ("bpf: pass bpf_struct_ops_link to callbacks in bpf_struct_ops.")

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/hid/bpf/hid_bpf_struct_ops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c
index 5f200557ff12b..744318e7d936b 100644
--- a/drivers/hid/bpf/hid_bpf_struct_ops.c
+++ b/drivers/hid/bpf/hid_bpf_struct_ops.c
@@ -175,7 +175,7 @@ static int hid_bpf_ops_init_member(const struct btf_type *t,
 	return 0;
 }
 
-static int hid_bpf_reg(void *kdata)
+static int hid_bpf_reg(void *kdata, struct bpf_link *link)
 {
 	struct hid_bpf_ops *ops = kdata;
 	struct hid_device *hdev;
@@ -229,7 +229,7 @@ static int hid_bpf_reg(void *kdata)
 	return err;
 }
 
-static void hid_bpf_unreg(void *kdata)
+static void hid_bpf_unreg(void *kdata, struct bpf_link *link)
 {
 	struct hid_bpf_ops *ops = kdata;
 	struct hid_device *hdev;
-- 
2.39.2


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

^ permalink raw reply related

* Re: [PATCH v11 1/5] firmware: cs_dsp: Add write sequence interface
From: James Ogletree @ 2024-06-17 15:06 UTC (permalink / raw)
  To: Charles Keepax
  Cc: James Ogletree, Dmitry Torokhov, robh+dt@kernel.org,
	Krzysztof Kozlowski, Conor Dooley, Lee Jones, Mark Brown,
	Jeff LaBundy, open list:CIRRUS LOGIC HAPTIC DRIVERS,
	linux-sound@vger.kernel.org, linux-input@vger.kernel.org,
	devicetree@vger.kernel.org
In-Reply-To: <ZmcXnL3xQ0IyJ6TF@opensource.cirrus.com>

Hi Charles,

> On Jun 10, 2024, at 10:11 AM, Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> 
> On Wed, Jun 05, 2024 at 01:52:45PM +0000, James Ogletree wrote:
>> A write sequence is a sequence of register addresses
>> and values executed by some Cirrus DSPs following
>> certain power state transitions.
>> 
>> Add support for Cirrus drivers to update or add to a
>> write sequence present in firmware.
>> 
>> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
>> Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
>> ---
> 
> I would suggest we just apply this patch, it is unlikely to
> change from review comments on the rest of the series and could
> well be useful to other parts in the meantime. It would also
> mean less traffic each time this series is sent up.
> 
> Thanks,
> Charles

Agreed with your points. I am okay with applying this separately.

Best,
James

^ permalink raw reply

* Re: [PATCH v11 3/5] mfd: cs40l50: Add support for CS40L50 core driver
From: James Ogletree @ 2024-06-17 15:05 UTC (permalink / raw)
  To: Lee Jones
  Cc: James Ogletree, Dmitry Torokhov, robh+dt@kernel.org,
	Krzysztof Kozlowski, Conor Dooley, Mark Brown, Jeff LaBundy,
	open list:CIRRUS LOGIC HAPTIC DRIVERS,
	open list:SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEM...,
	open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <20240614080820.GC2561462@google.com>



> On Jun 14, 2024, at 3:08 AM, Lee Jones <lee@kernel.org> wrote:
> 
> On Wed, 05 Jun 2024, James Ogletree wrote:
> 
>> Introduce support for Cirrus Logic Device CS40L50: a
>> haptic driver with waveform memory, integrated DSP,
>> and closed-loop algorithms.
>> 
>> The MFD component registers and initializes the device.
>> 
>> Signed-off-by: James Ogletree <jogletre@opensource.cirrus.com>
>> ---
>> MAINTAINERS                 |   2 +
>> drivers/mfd/Kconfig         |  30 ++
>> drivers/mfd/Makefile        |   4 +
>> drivers/mfd/cs40l50-core.c  | 570 ++++++++++++++++++++++++++++++++++++
>> drivers/mfd/cs40l50-i2c.c   |  68 +++++
>> drivers/mfd/cs40l50-spi.c   |  68 +++++
>> include/linux/mfd/cs40l50.h | 137 +++++++++
>> 7 files changed, 879 insertions(+)
>> create mode 100644 drivers/mfd/cs40l50-core.c
>> create mode 100644 drivers/mfd/cs40l50-i2c.c
>> create mode 100644 drivers/mfd/cs40l50-spi.c
>> create mode 100644 include/linux/mfd/cs40l50.h
> 
> This is good to go now.
> 
> Ping me once you have all your other Acks and I'll merge the set.
> 
> -- 
> Lee Jones [李琼斯]

Will do. Thank you.

Best,
James

^ permalink raw reply

* [PATCH AUTOSEL 4.19 6/9] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-17 13:27 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240617132757.2590643-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index a787a6aefc69f..78f08ca3f8442 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -78,7 +78,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -106,7 +105,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
 	touchscreen_parse_properties(data->input, true, &data->prop);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -153,10 +152,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	touch_nr = 0;
@@ -208,7 +207,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -218,7 +216,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -445,13 +443,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 5.4 6/9] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-17 13:27 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240617132739.2590390-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index c8776146f1d1b..467feacdbd7a2 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -70,7 +70,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -98,7 +97,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
 	touchscreen_parse_properties(data->input, true, &data->prop);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -145,10 +144,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	touch_nr = 0;
@@ -200,7 +199,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -210,7 +208,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -437,13 +435,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 5.10 07/13] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-17 13:26 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240617132710.2590101-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index e8b6c3137420b..901e28bc01645 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -70,7 +70,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -98,7 +97,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
 	touchscreen_parse_properties(data->input, true, &data->prop);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -145,10 +144,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	touch_nr = 0;
@@ -200,7 +199,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -210,7 +208,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -437,13 +435,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 5.15 15/21] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-17 13:25 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240617132617.2589631-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 1ee760bac0cfa..3be59b7239a68 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -70,7 +70,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -98,7 +97,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
 	touchscreen_parse_properties(data->input, true, &data->prop);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -145,10 +144,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	touch_nr = 0;
@@ -200,7 +199,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -210,7 +208,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -437,13 +435,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.1 29/29] HID: Ignore battery for ELAN touchscreens 2F2C and 4116
From: Sasha Levin @ 2024-06-17 13:24 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Louis Dalibard, Jiri Kosina, Sasha Levin, jikos, bentiss,
	linux-input
In-Reply-To: <20240617132456.2588952-1-sashal@kernel.org>

From: Louis Dalibard <ontake@ontake.dev>

[ Upstream commit a3a5a37efba11b7cf1a86abe7bccfbcdb521764e ]

At least ASUS Zenbook 14 (2023) and ASUS Zenbook 14 Pro (2023) are affected.

The touchscreen reports a battery status of 0% and jumps to 1% when a
stylus is used.

The device ID was added and the battery ignore quirk was enabled for it.

[jkosina@suse.com: reformatted changelog a bit]
Signed-off-by: Louis Dalibard <ontake@ontake.dev>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/hid/hid-ids.h   | 2 ++
 drivers/hid/hid-input.c | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 405d88b08908d..4b8c1d18c21e0 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -417,6 +417,8 @@
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG  0x29DF
 #define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8
 #define I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN 0x2C82
+#define I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN 0x2F2C
+#define I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN 0x4116
 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN	0x2544
 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN	0x2706
 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN	0x261A
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 4ba5df3c1e039..b0091819fd58a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -374,6 +374,10 @@ static const struct hid_device_id hid_battery_quirks[] = {
 	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN),
 	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN),
+	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN),
+	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
 	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.1 23/29] Input: silead - Always support 10 fingers
From: Sasha Levin @ 2024-06-17 13:24 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Hans de Goede, Dmitry Torokhov, Sasha Levin, linux-input,
	platform-driver-x86
In-Reply-To: <20240617132456.2588952-1-sashal@kernel.org>

From: Hans de Goede <hdegoede@redhat.com>

[ Upstream commit 38a38f5a36da9820680d413972cb733349400532 ]

When support for Silead touchscreens was orginal added some touchscreens
with older firmware versions only supported 5 fingers and this was made
the default requiring the setting of a "silead,max-fingers=10" uint32
device-property for all touchscreen models which do support 10 fingers.

There are very few models with the old 5 finger fw, so in practice the
setting of the "silead,max-fingers=10" is boilerplate which needs to
be copy and pasted to every touchscreen config.

Reporting that 10 fingers are supported on devices which only support
5 fingers doesn't cause any problems for userspace in practice, since
at max 4 finger gestures are supported anyways. Drop the max_fingers
configuration and simply always assume 10 fingers.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20240525193854.39130-2-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/input/touchscreen/silead.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 3eef8c01090fd..30e15b6a93574 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -71,7 +71,6 @@ struct silead_ts_data {
 	struct regulator_bulk_data regulators[2];
 	char fw_name[64];
 	struct touchscreen_properties prop;
-	u32 max_fingers;
 	u32 chip_id;
 	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
 	int slots[SILEAD_MAX_FINGERS];
@@ -136,7 +135,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
 	touchscreen_parse_properties(data->input, true, &data->prop);
 	silead_apply_efi_fw_min_max(data);
 
-	input_mt_init_slots(data->input, data->max_fingers,
+	input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
 			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
 			    INPUT_MT_TRACK);
 
@@ -256,10 +255,10 @@ static void silead_ts_read_data(struct i2c_client *client)
 		return;
 	}
 
-	if (buf[0] > data->max_fingers) {
+	if (buf[0] > SILEAD_MAX_FINGERS) {
 		dev_warn(dev, "More touches reported then supported %d > %d\n",
-			 buf[0], data->max_fingers);
-		buf[0] = data->max_fingers;
+			 buf[0], SILEAD_MAX_FINGERS);
+		buf[0] = SILEAD_MAX_FINGERS;
 	}
 
 	if (silead_ts_handle_pen_data(data, buf))
@@ -315,7 +314,6 @@ static void silead_ts_read_data(struct i2c_client *client)
 
 static int silead_ts_init(struct i2c_client *client)
 {
-	struct silead_ts_data *data = i2c_get_clientdata(client);
 	int error;
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -325,7 +323,7 @@ static int silead_ts_init(struct i2c_client *client)
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
 
 	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
-					data->max_fingers);
+					  SILEAD_MAX_FINGERS);
 	if (error)
 		goto i2c_write_err;
 	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -591,13 +589,6 @@ static void silead_ts_read_props(struct i2c_client *client)
 	const char *str;
 	int error;
 
-	error = device_property_read_u32(dev, "silead,max-fingers",
-					 &data->max_fingers);
-	if (error) {
-		dev_dbg(dev, "Max fingers read error %d\n", error);
-		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
-	}
-
 	error = device_property_read_string(dev, "firmware-name", &str);
 	if (!error)
 		snprintf(data->fw_name, sizeof(data->fw_name),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.6 35/35] HID: Ignore battery for ELAN touchscreens 2F2C and 4116
From: Sasha Levin @ 2024-06-17 13:22 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Louis Dalibard, Jiri Kosina, Sasha Levin, jikos, bentiss,
	linux-input
In-Reply-To: <20240617132309.2588101-1-sashal@kernel.org>

From: Louis Dalibard <ontake@ontake.dev>

[ Upstream commit a3a5a37efba11b7cf1a86abe7bccfbcdb521764e ]

At least ASUS Zenbook 14 (2023) and ASUS Zenbook 14 Pro (2023) are affected.

The touchscreen reports a battery status of 0% and jumps to 1% when a
stylus is used.

The device ID was added and the battery ignore quirk was enabled for it.

[jkosina@suse.com: reformatted changelog a bit]
Signed-off-by: Louis Dalibard <ontake@ontake.dev>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/hid/hid-ids.h   | 2 ++
 drivers/hid/hid-input.c | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0a4daff4846ff..cee09538c9aa2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -418,6 +418,8 @@
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG  0x29DF
 #define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8
 #define I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN 0x2C82
+#define I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN 0x2F2C
+#define I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN 0x4116
 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN	0x2544
 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN	0x2706
 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN	0x261A
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 8bb16e9b94aa5..c9094a4f281e9 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -377,6 +377,10 @@ static const struct hid_device_id hid_battery_quirks[] = {
 	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN),
 	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN),
+	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN),
+	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
 	  HID_BATTERY_QUIRK_IGNORE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
-- 
2.43.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.6 34/35] input: Add support for "Do Not Disturb"
From: Sasha Levin @ 2024-06-17 13:22 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Aseda Aboagye, Dmitry Torokhov, Benjamin Tissoires, Sasha Levin,
	jikos, linux-input
In-Reply-To: <20240617132309.2588101-1-sashal@kernel.org>

From: Aseda Aboagye <aaboagye@chromium.org>

[ Upstream commit 22d6d060ac77955291deb43efc2f3f4f9632c6cb ]

HUTRR94 added support for a new usage titled "System Do Not Disturb"
which toggles a system-wide Do Not Disturb setting. This commit simply
adds a new event code for the usage.

Signed-off-by: Aseda Aboagye <aaboagye@chromium.org>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/Zl-gUHE70s7wCAoB@google.com
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/hid/hid-debug.c                | 1 +
 drivers/hid/hid-input.c                | 8 ++++++++
 include/uapi/linux/input-event-codes.h | 1 +
 3 files changed, 10 insertions(+)

diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index c629ab161d5b2..5302bfd527d86 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -975,6 +975,7 @@ static const char *keys[KEY_MAX + 1] = {
 	[KEY_CAMERA_ACCESS_DISABLE] = "CameraAccessDisable",
 	[KEY_CAMERA_ACCESS_TOGGLE] = "CameraAccessToggle",
 	[KEY_ACCESSIBILITY] = "Accessibility",
+	[KEY_DO_NOT_DISTURB] = "DoNotDisturb",
 	[KEY_DICTATE] = "Dictate",
 	[KEY_MICMUTE] = "MicrophoneMute",
 	[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d5a6e89c3086e..8bb16e9b94aa5 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -833,6 +833,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			break;
 		}
 
+		if ((usage->hid & 0xf0) == 0x90) { /* SystemControl*/
+			switch (usage->hid & 0xf) {
+			case 0xb: map_key_clear(KEY_DO_NOT_DISTURB); break;
+			default: goto ignore;
+			}
+			break;
+		}
+
 		if ((usage->hid & 0xf0) == 0xa0) {	/* SystemControl */
 			switch (usage->hid & 0xf) {
 			case 0x9: map_key_clear(KEY_MICMUTE); break;
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 39f11ec676fae..a4206723f5033 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -619,6 +619,7 @@
 #define KEY_CAMERA_ACCESS_DISABLE	0x24c	/* Disables programmatic access to camera devices. (HUTRR72) */
 #define KEY_CAMERA_ACCESS_TOGGLE	0x24d	/* Toggles the current state of the camera access control. (HUTRR72) */
 #define KEY_ACCESSIBILITY		0x24e	/* Toggles the system bound accessibility UI/command (HUTRR116) */
+#define KEY_DO_NOT_DISTURB		0x24f	/* Toggles the system-wide "Do Not Disturb" control (HUTRR94)*/
 
 #define KEY_BRIGHTNESS_MIN		0x250	/* Set Brightness to Minimum */
 #define KEY_BRIGHTNESS_MAX		0x251	/* Set Brightness to Maximum */
-- 
2.43.0


^ permalink raw reply related


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