From nobody Thu Apr 9 16:34:57 2026 Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0390382F39 for ; Tue, 3 Mar 2026 06:13:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772518441; cv=none; b=aokGys6bx5ZgL3nfRL8zS4AbenR4xfr37gmTL5AiEpUct1fgAu+4ybz6y+dPosXYj3TEFVAEJu7/Hq+vVrZxdhVd7C4MOzJqKih0si2BzQSBU5WZlOPzcQwZuMXhaAKZpJXlxZ8mKa5dhLQa9wJoT6eXXLEY6JWYJ0Lxsftx7zk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772518441; c=relaxed/simple; bh=RuF4EBelwWjX4MVB7wRAKwjHLIyH356VR5EZd3QmjHw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ApVYojkm99SJYFfSkU1w0+pXOIIFRuZ3bbmPt0M5gE4ZAZKfJ0LPKdI1gHW9b+5Acfsn8a3oL8Mr6qXoHrQs14p63WpFPlGu2pCJHL/wxQIiBz7DW6Ue94MFcBzEGOYLI4B7hMNaoyGBI0Gx1dO+YWi5vRNPFeVH/9YpA5SYpwI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=e+9q8H9Z; arc=none smtp.client-ip=209.85.214.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="e+9q8H9Z" Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-2ae46fc8ec1so14459585ad.3 for ; Mon, 02 Mar 2026 22:13:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1772518437; x=1773123237; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=iTYYpNGe7aJcDLJJdiqjkV8VqGfZqV4Qv94rVv/ZSwU=; b=e+9q8H9Z2qaUbup2uhMXSUAKhFg4kP8EaZTJCDbEtlMY+sjG2idWUzGG1GalnklDbq raUw8Zf/h+acrwI14KJAwQvza07p9H78YbNaSXlXXCEIVKfAC/pgoJmTo9aVbwrhqhh7 3BFB1AizMh3VTRYKE5TM+u5QAbuW000RDS1hM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772518437; x=1773123237; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=iTYYpNGe7aJcDLJJdiqjkV8VqGfZqV4Qv94rVv/ZSwU=; b=t3R8L1x/7gH1qQtJn8FjlH9pXKGuWAOlmY+LMGC1dzCIloJVXZMb8RGZsYGqxCul9E iFoc7yXxezrA/DDep64ggFQQGlB1GCFaNeSYUBObQFrhQirWt64Q29f0mNCd+/COlLUe LQSmVyHjOua3aGtRLdk4mTG/Pbdrl4KCfX/bNW2BRWI+fW2Z6N9dvJUpFr1iP4u2FF2P dZL6Fopsrp3Hj6/1V1KkjXt0YLEeSv+SvQkk77K+Yh8ifMnhPB01oFt7f4wp9Be2bSKl xM/KXVt0lfEsXMAljhpKV677by5offIIn+uLHmTi/W8o20KK5Rxe6jA/hpiPF3o61opK HLGg== X-Forwarded-Encrypted: i=1; AJvYcCXlWMrUPIeOdlQXVf496mt1AVMNuhfBq4jBfUZvdHvepA58VPsA++mZM3BQ7leloKK8S8htOH/WbAt2zVE=@vger.kernel.org X-Gm-Message-State: AOJu0YwZCTrHR2NQGFI9QAD3srLJzTO8pLAMe/Dre/rBDWOJYf7/e9KK L8ZuJdPa4CZye85cCOpUZuYjLqrdoVnRxmlYZ46YnK0+pWKPWSob0TsQ/fPDX8kESA== X-Gm-Gg: ATEYQzwlCEz//P/JOoe85pQdVr1ILCqoNTfd+luizWu4zzQNiLYukN+SRmzejIpRXdq X6EgOhXd6MDre+wVkTbw+ukZquIJC2ZDn7aUf3jrNjXfeCTWVf+u+ivkSjKSKRPOQZj0xGtkmTJ DEBFAWuU3wZb0TVLN6X4LoXcvRb8XnbBX0wMrqgy2prQbs0G57xUvBfoaEs+V7EvPHxIcgFh81x l0rQ0Ipf9iQNonzTPpqB1zg/0xOy9DVBcF9iM/QRBEduE7nIMvSwgJY6gwAzv7amMHKaJYBSUE/ OastG1mkBFFfGeVMCMJaeNwe0WdQjfmCj7pxWOI9JnFX5AnWOIG6TnGoQxkQo5g8FTub280CCd3 5DQp+bljK0nzdVd2c3hKzfaTKQaHYF2CmfZ6nRCdMavrYoM4K8OkhxZ3CN/wCCElaR2uA08GqIl vzrFwnpSpAS05PbhRda0hXEjM1aUhBS/HSyeQtOSx4gKHsBQfujSX6nPeWG7ePWimUdmOPkjM9I kzeVcwytBHv8b2tT733V7S50T0dfSmcKw== X-Received: by 2002:a17:903:b0d:b0:2ae:5598:1db3 with SMTP id d9443c01a7336-2ae55982a32mr46227035ad.53.1772518437154; Mon, 02 Mar 2026 22:13:57 -0800 (PST) Received: from jingyliang-input-linux.c.googlers.com (111.169.168.34.bc.googleusercontent.com. [34.168.169.111]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2adfb6fe4f3sm152639735ad.91.2026.03.02.22.13.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Mar 2026 22:13:56 -0800 (PST) From: Jingyuan Liang Date: Tue, 03 Mar 2026 06:13:04 +0000 Subject: [PATCH 12/12] HID: spi-hid: add quirkis to support mode switch for Ilitek touch Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260303-send-upstream-v1-12-1515ba218f3d@chromium.org> References: <20260303-send-upstream-v1-0-1515ba218f3d@chromium.org> In-Reply-To: <20260303-send-upstream-v1-0-1515ba218f3d@chromium.org> To: Jiri Kosina , Benjamin Tissoires , Jonathan Corbet , Mark Brown , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-input@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, linux-trace-kernel@vger.kernel.org, devicetree@vger.kernel.org, hbarnor@chromium.org, Jingyuan Liang X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1772518424; l=7060; i=jingyliang@chromium.org; s=20260213; h=from:subject:message-id; bh=RuF4EBelwWjX4MVB7wRAKwjHLIyH356VR5EZd3QmjHw=; b=yqf3lINoDU5izp7XLxBncUEfy96hR5Uvs/pFDvxmmcHDmeFoqVujMRkAE6X/GypO/8SUjW/3o lT326CxlFyPDmz4HEgVb+PXKKZ5GIdZgPXaG1pCF1ZDP2sH2scC1goy X-Developer-Key: i=jingyliang@chromium.org; a=ed25519; pk=VTYSdqslTtYOjWWoIGgYoWupGWqNSidrggReKMgfPo4= Add quirks to support mode switch among Ilitek normal, debug and test mode and allow delay before send output reports. Add a shared variable to configure response timeout value for Ilitek touch controllers. Signed-off-by: Jingyuan Liang --- drivers/hid/spi-hid/spi-hid-core.c | 84 ++++++++++++++++++++++++++++++++++= +++- drivers/hid/spi-hid/spi-hid-core.h | 4 ++ drivers/hid/spi-hid/spi-hid.h | 6 +++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-h= id-core.c index 893a0d4642d2..736e51f10cfc 100644 --- a/drivers/hid/spi-hid/spi-hid-core.c +++ b/drivers/hid/spi-hid/spi-hid-core.c @@ -22,6 +22,7 @@ =20 #include #include +#include #include #include #include @@ -45,9 +46,14 @@ #include #include =20 +#include "../hid-ids.h" #include "spi-hid.h" #include "spi-hid-core.h" =20 +/* quirks to control the device */ +#define SPI_HID_QUIRK_MODE_SWITCH BIT(0) +#define SPI_HID_QUIRK_READ_DELAY BIT(1) + /* Protocol constants */ #define SPI_HID_READ_APPROVAL_CONSTANT 0xff #define SPI_HID_INPUT_HEADER_SYNC_BYTE 0x5a @@ -86,6 +92,16 @@ #define SPI_HID_CREATE_DEVICE 4 #define SPI_HID_ERROR 5 =20 +static const struct spi_hid_quirks { + __u16 idVendor; + __u16 idProduct; + __u32 quirks; +} spi_hid_quirks[] =3D { + { USB_VENDOR_ID_ILITEK, HID_ANY_ID, + SPI_HID_QUIRK_MODE_SWITCH | SPI_HID_QUIRK_READ_DELAY }, + { 0, 0 } +}; + /* Processed data from input report header */ struct spi_hid_input_header { u8 version; @@ -112,6 +128,27 @@ struct spi_hid_output_report { =20 static struct hid_ll_driver spi_hid_ll_driver; =20 +/** + * spi_hid_lookup_quirk: return any quirks associated with a SPI HID device + * @idVendor: the 16-bit vendor ID + * @idProduct: the 16-bit product ID + * + * Returns: a u32 quirks value. + */ +static u32 spi_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) +{ + u32 quirks =3D 0; + int n; + + for (n =3D 0; spi_hid_quirks[n].idVendor; n++) + if (spi_hid_quirks[n].idVendor =3D=3D idVendor && + (spi_hid_quirks[n].idProduct =3D=3D (__u16)HID_ANY_ID || + spi_hid_quirks[n].idProduct =3D=3D idProduct)) + quirks =3D spi_hid_quirks[n].quirks; + + return quirks; +} + static void spi_hid_populate_read_approvals(const struct spi_hid_conf *con= f, u8 *header_buf, u8 *body_buf) { @@ -382,6 +419,9 @@ static int spi_hid_send_output_report(struct spi_hid *s= hid, u8 padding; int error; =20 + if (shid->quirks & SPI_HID_QUIRK_READ_DELAY) + usleep_range(2000, 2100); + guard(mutex)(&shid->output_lock); if (report->content_length > shid->desc.max_output_length) { dev_err(dev, "Output report too big, content_length 0x%x.", @@ -406,18 +446,38 @@ static int spi_hid_send_output_report(struct spi_hid = *shid, return error; } =20 +static const u32 spi_hid_get_timeout(struct spi_hid *shid) +{ + struct device *dev =3D &shid->spi->dev; + u32 timeout; + + timeout =3D READ_ONCE(shid->ops->response_timeout_ms); + + if (timeout < SPI_HID_RESP_TIMEOUT || timeout > 10000) { + dev_dbg(dev, "Response timeout is out of range, using default %d", + SPI_HID_RESP_TIMEOUT); + timeout =3D SPI_HID_RESP_TIMEOUT; + } + + return timeout; +} + static int spi_hid_sync_request(struct spi_hid *shid, struct spi_hid_output_report *report) { struct device *dev =3D &shid->spi->dev; + u32 timeout =3D SPI_HID_RESP_TIMEOUT; int error; =20 error =3D spi_hid_send_output_report(shid, report); if (error) return error; =20 + if (shid->quirks & SPI_HID_QUIRK_MODE_SWITCH) + timeout =3D spi_hid_get_timeout(shid); + error =3D wait_for_completion_interruptible_timeout(&shid->output_done, - msecs_to_jiffies(SPI_HID_RESP_TIMEOUT)); + msecs_to_jiffies(timeout)); if (error =3D=3D 0) { dev_err(dev, "Response timed out."); return -ETIMEDOUT; @@ -561,6 +621,8 @@ static int spi_hid_create_device(struct spi_hid *shid) hid->vendor =3D shid->desc.vendor_id; hid->product =3D shid->desc.product_id; =20 + shid->quirks =3D spi_hid_lookup_quirk(hid->vendor, hid->product); + snprintf(hid->name, sizeof(hid->name), "spi %04X:%04X", hid->vendor, hid->product); strscpy(hid->phys, dev_name(&shid->spi->dev), sizeof(hid->phys)); @@ -836,6 +898,24 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shi= d) goto out; } =20 + if (shid->quirks & SPI_HID_QUIRK_MODE_SWITCH) { + /* + * Update reset_pending on mode transitions inferred from + * response timeout (entering/exiting a mode). + */ + u32 timeout =3D spi_hid_get_timeout(shid); + bool mode_enabled =3D timeout > SPI_HID_RESP_TIMEOUT; + + if (mode_enabled !=3D shid->prev_mode_enabled) { + if (mode_enabled) + set_bit(SPI_HID_RESET_PENDING, &shid->flags); + else + clear_bit(SPI_HID_RESET_PENDING, &shid->flags); + } + + shid->prev_mode_enabled =3D mode_enabled; + } + if (shid->input_message.status < 0) { dev_warn(dev, "Error reading header: %d.", shid->input_message.status); @@ -1190,6 +1270,8 @@ static int spi_hid_dev_init(struct spi_hid *shid) struct device *dev =3D &spi->dev; int error; =20 + shid->ops->custom_init(shid->ops); + shid->ops->assert_reset(shid->ops); =20 shid->ops->sleep_minimal_reset_delay(shid->ops); diff --git a/drivers/hid/spi-hid/spi-hid-core.h b/drivers/hid/spi-hid/spi-h= id-core.h index 88e9020d37aa..8441dbad95d4 100644 --- a/drivers/hid/spi-hid/spi-hid-core.h +++ b/drivers/hid/spi-hid/spi-hid-core.h @@ -62,6 +62,10 @@ struct spi_hid { u16 response_length; u16 bufsize; =20 + bool prev_mode_enabled; /* Previous device mode tracked for SPI_HID_QUIRK= _MODE_SWITCH. */ + + unsigned long quirks; /* Various quirks. */ + enum hidspi_power_state power_state; =20 u8 reset_attempts; /* The number of reset attempts. */ diff --git a/drivers/hid/spi-hid/spi-hid.h b/drivers/hid/spi-hid/spi-hid.h index 5651c7fb706a..3c0369bdb4ab 100644 --- a/drivers/hid/spi-hid/spi-hid.h +++ b/drivers/hid/spi-hid/spi-hid.h @@ -25,6 +25,9 @@ struct spi_hid_conf { * @power_down: do sequencing to power down the device * @assert_reset: do sequencing to assert the reset line * @deassert_reset: do sequencing to deassert the reset line + * @sleep_minimal_reset_delay: minimal sleep delay during reset + * @custom_init: customized device init + * @response_timeout_ms: output report response timeout in ms */ struct spihid_ops { int (*power_up)(struct spihid_ops *ops); @@ -32,6 +35,9 @@ struct spihid_ops { int (*assert_reset)(struct spihid_ops *ops); int (*deassert_reset)(struct spihid_ops *ops); void (*sleep_minimal_reset_delay)(struct spihid_ops *ops); + int (*custom_init)(struct spihid_ops *ops); + + u32 response_timeout_ms; }; =20 int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, --=20 2.53.0.473.g4a7958ca14-goog