From be8f7f2281a26abbda26ce37c5ee4674022a7a2f Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Thu, 31 Oct 2024 20:31:12 +0800 Subject: [PATCH 1/4] HID: hid-goodix: Return 0 when receiving an empty HID feature package Align with the i2c-hid driver by returning 0 instead of -EINVAL when an empty response is received, ensuring that userspace programs utilizing the hidraw node receive consistent return values. Signed-off-by: Charles Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-goodix-spi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c index 0f87bf9c67cf..077a91ee1d37 100644 --- a/drivers/hid/hid-goodix-spi.c +++ b/drivers/hid/hid-goodix-spi.c @@ -356,7 +356,7 @@ static int goodix_hid_check_ack_status(struct goodix_ts_data *ts, u32 *resp_len) dev_err(ts->dev, "hrd.size too short: %d", len); return -EINVAL; } - *resp_len = len; + *resp_len = len - GOODIX_HID_PKG_LEN_SIZE; return 0; } @@ -446,7 +446,10 @@ static int goodix_hid_get_raw_report(struct hid_device *hid, if (error) return error; - len = min(len, response_data_len - GOODIX_HID_PKG_LEN_SIZE); + /* Empty reprot response */ + if (!response_data_len) + return 0; + len = min(len, response_data_len); /* Step3: read response data(skip 2bytes of hid pkg length) */ error = goodix_spi_read(ts, ts->hid_report_addr + GOODIX_HID_ACK_HEADER_SIZE + From 253ed2740be0267ef75b181767b1999ab755bb84 Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Thu, 31 Oct 2024 20:31:13 +0800 Subject: [PATCH 2/4] HID: hid-goodix: Fix HID get/set feature operation overwritten problem Implement the hid get/set feature report function using a separate address, rather than sharing an address with coordinate reporting, to prevent feature events from being overwritten by coordinate events. Signed-off-by: Charles Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-goodix-spi.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c index 077a91ee1d37..6ae2300a603e 100644 --- a/drivers/hid/hid-goodix-spi.c +++ b/drivers/hid/hid-goodix-spi.c @@ -19,6 +19,7 @@ #define GOODIX_HID_DESC_ADDR 0x1058C #define GOODIX_HID_REPORT_DESC_ADDR 0x105AA #define GOODIX_HID_SIGN_ADDR 0x10D32 +#define GOODIX_HID_CMD_ADDR 0x10364 #define GOODIX_HID_GET_REPORT_CMD 0x02 #define GOODIX_HID_SET_REPORT_CMD 0x03 @@ -348,7 +349,7 @@ static int goodix_hid_check_ack_status(struct goodix_ts_data *ts, u32 *resp_len) * - 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, + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR, &hdr, sizeof(hdr)); if (!error && (hdr.flag & GOODIX_HID_ACK_READY_FLAG)) { len = le16_to_cpu(hdr.size); @@ -431,7 +432,7 @@ static int goodix_hid_get_raw_report(struct hid_device *hid, tx_len += args_len; /* Step1: write report request info */ - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); if (error) { dev_err(ts->dev, "failed send read feature cmd, %d", error); return error; @@ -451,7 +452,7 @@ static int goodix_hid_get_raw_report(struct hid_device *hid, return 0; len = min(len, response_data_len); /* Step3: read response data(skip 2bytes of hid pkg length) */ - error = goodix_spi_read(ts, ts->hid_report_addr + + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR + GOODIX_HID_ACK_HEADER_SIZE + GOODIX_HID_PKG_LEN_SIZE, buf, len); if (error) { @@ -521,7 +522,7 @@ static int goodix_hid_set_raw_report(struct hid_device *hid, memcpy(tmp_buf + tx_len, buf, len); tx_len += len; - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); if (error) { dev_err(ts->dev, "failed send report: %*ph", tx_len, tmp_buf); return error; @@ -752,7 +753,7 @@ static int goodix_spi_set_power(struct goodix_ts_data *ts, int power_state) power_control_cmd[5] = power_state; guard(mutex)(&ts->hid_request_lock); - error = goodix_spi_write(ts, ts->hid_report_addr, power_control_cmd, + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, power_control_cmd, sizeof(power_control_cmd)); if (error) { dev_err(ts->dev, "failed set power mode: %s", From 20bcb2734bafa2adfbf8fc62542c742df9c46cfd Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Mon, 11 Nov 2024 15:49:59 +0800 Subject: [PATCH 3/4] dt-bindings: input: Goodix GT7986U SPI HID Touchscreen 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. NOTE: these bindings are distinct from the bindings used with the GT7986U when the chip is running I2C firmware. For some background, see discussion on the mailing lists in the thread: https://lore.kernel.org/r/20241018020815.3098263-2-charles.goodix@gmail.com Signed-off-by: Charles Wang Reviewed-by: Douglas Anderson Reviewed-by: Rob Herring (Arm) Signed-off-by: Jiri Kosina --- .../bindings/input/goodix,gt7986u-spifw.yaml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml diff --git a/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml b/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml new file mode 100644 index 000000000000..92bd0041feba --- /dev/null +++ b/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/goodix,gt7986u-spifw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Goodix GT7986U SPI HID Touchscreen + +maintainers: + - Charles Wang + +description: | + Supports the Goodix GT7986U touchscreen. + This touch controller reports data packaged according to the HID protocol + over the SPI bus, but it is incompatible with Microsoft's HID-over-SPI protocol. + + NOTE: these bindings are distinct from the bindings used with the + GT7986U when the chip is running I2C firmware. This is because there's + not a single device that talks over both I2C and SPI but rather + distinct touchscreens that happen to be built with the same ASIC but + that are distinct products running distinct firmware. + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - goodix,gt7986u-spifw + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + spi-max-frequency: true + +required: + - compatible + - reg + - interrupts + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@0 { + compatible = "goodix,gt7986u-spifw"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + spi-max-frequency = <10000000>; + }; + }; + +... From c8eb2faef11866be7802ff2ce9852890bcfcde16 Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Mon, 11 Nov 2024 15:50:00 +0800 Subject: [PATCH 4/4] HID: hid-goodix-spi: Add OF supports This patch introduces the following changes: - Adds OF match table. - Hardcodes hid-report-addr in the driver rather than fetching it from the device property. Signed-off-by: Charles Wang Reviewed-by: Douglas Anderson Signed-off-by: Jiri Kosina --- drivers/hid/hid-goodix-spi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c index 6ae2300a603e..80c0288a3a38 100644 --- a/drivers/hid/hid-goodix-spi.c +++ b/drivers/hid/hid-goodix-spi.c @@ -20,6 +20,7 @@ #define GOODIX_HID_REPORT_DESC_ADDR 0x105AA #define GOODIX_HID_SIGN_ADDR 0x10D32 #define GOODIX_HID_CMD_ADDR 0x10364 +#define GOODIX_HID_REPORT_ADDR 0x22C8C #define GOODIX_HID_GET_REPORT_CMD 0x02 #define GOODIX_HID_SET_REPORT_CMD 0x03 @@ -701,12 +702,7 @@ static int goodix_spi_probe(struct spi_device *spi) 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"); - + ts->hid_report_addr = GOODIX_HID_REPORT_ADDR; error = goodix_dev_confirm(ts); if (error) return error; @@ -790,6 +786,14 @@ static const struct acpi_device_id goodix_spi_acpi_match[] = { 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-spifw", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_spi_of_match); +#endif + static const struct spi_device_id goodix_spi_ids[] = { { "gt7986u" }, { }, @@ -800,6 +804,7 @@ 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,