.../intel-quickspi/pci-quickspi.c | 32 +++++++++++++++++++ .../intel-quickspi/quickspi-dev.h | 4 +++ 2 files changed, 36 insertions(+)
Hi,
Sorry, I cannot get your exact name from this patch email.
From your issue description, I suppose Surface Pro 10 uses "Suspend-to-RAM" instead of "Standby" or "Suspend-to-Idle" for suspend/resume.
As this documents mentioned, driver needs to take care the suspend type then handle resume flow carefully.
Actually, I had a patch for this "Suspend-to-RAM" support several months ago, please find attached file for the patch. This patch is still under our internal final validation.
It will be very appreciated if you can help test attached patch on your Surface device.
If it works, then everything is fine, I will submit this patch with your name after our final validation.
If it doesn't work for your case, then we need to future debug on your surface device to refine your patch to let it more standard.
Thanks!
Best Regards,
Even Xu
> -----Original Message-----
> From: d3z-the-dev <d3z.the.dev@gmail.com>
> Sent: Saturday, May 30, 2026 6:22 AM
> To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>; Jiri
> Kosina <jikos@kernel.org>; Benjamin Tissoires <bentiss@kernel.org>
> Cc: linux-input@vger.kernel.org; linux-kernel@vger.kernel.org; Abhishek Tamboli
> <abhishektamboli9@gmail.com>; Sakari Ailus <sakari.ailus@linux.intel.com>;
> d3z-the-dev <d3z.the.dev@gmail.com>
> Subject: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on system
> resume
>
> On the Surface Pro 10 (Meteor Lake) the touchscreen stops working after a
> suspend/resume cycle and only recovers after a reboot. The driver logs
> "GET_DEVICE_INFO: recv failed: -11" on resume.
>
> The touch IC loses power during system suspend (s2idle) on this platform, the
> same way it does across hibernation. quickspi_resume() only restores the THC
> port, interrupts and DMA and sends a HIDSPI_ON command, assuming the touch
> IC kept its power and state. When it has actually lost power the HIDSPI_ON
> command is never acknowledged and the descriptor read fails, leaving the
> touchscreen dead until the module is reloaded.
>
> quickspi_restore() already handles this for hibernation by running
> reset_tic() and reconfiguring the THC SPI/LTR settings. Make
> quickspi_resume() do the same: quiesce interrupts, re-select the THC port,
> reconfigure the SPI input/output addresses and read/write parameters, run
> reset_tic() to re-enumerate the device and restore the LTR configuration.
>
> Tested on a Surface Pro 10 across multiple s2idle suspend/resume cycles.
>
> Link: https://github.com/linux-surface/linux-surface/issues/1799
>
> Signed-off-by: d3z-the-dev <d3z.the.dev@gmail.com>
> ---
> .../intel-quickspi/pci-quickspi.c | 38 +++++++++++++++++--
> 1 file changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
> b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
> index f669235f1883..d59278a3e5c1 100644
> --- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
> +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
> @@ -780,24 +780,54 @@ static int quickspi_resume(struct device *device)
> if (!qsdev)
> return -ENODEV;
>
> + ret = thc_interrupt_quiesce(qsdev->thc_hw, true);
> + if (ret)
> + return ret;
> +
> ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI);
> if (ret)
> return ret;
>
> + thc_spi_input_output_address_config(qsdev->thc_hw,
> + qsdev->input_report_hdr_addr,
> + qsdev->input_report_bdy_addr,
> + qsdev->output_report_addr);
> +
> + ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val,
> + qsdev->spi_read_io_mode,
> + qsdev->spi_read_opcode,
> + qsdev->spi_packet_size);
> + if (ret)
> + return ret;
> +
> + ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val,
> + qsdev->spi_write_io_mode,
> + qsdev->spi_write_opcode,
> + qsdev->spi_packet_size,
> + qsdev->performance_limit);
> + if (ret)
> + return ret;
> +
> thc_interrupt_config(qsdev->thc_hw);
>
> thc_interrupt_enable(qsdev->thc_hw, true);
>
> - ret = thc_dma_configure(qsdev->thc_hw);
> + /* The TIC may lose power across system suspend, reset it to recover */
> + ret = reset_tic(qsdev);
> if (ret)
> return ret;
>
> - ret = thc_interrupt_quiesce(qsdev->thc_hw, false);
> + ret = thc_dma_configure(qsdev->thc_hw);
> if (ret)
> return ret;
>
> - if (!device_may_wakeup(qsdev->dev))
> - return quickspi_set_power(qsdev, HIDSPI_ON);
> + thc_ltr_config(qsdev->thc_hw,
> + qsdev->active_ltr_val,
> + qsdev->low_power_ltr_val);
> +
> + thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE);
> +
> + qsdev->state = QUICKSPI_ENABLED;
>
> return 0;
> }
> --
> 2.54.0
From 939ec2c491f789b5b740a58936ff0e04cb71d2a8 Mon Sep 17 00:00:00 2001
From: Even Xu <even.xu@intel.com>
Date: Mon, 19 Jan 2026 16:16:12 +0800
Subject: [PATCH] Hid: Intel-thc-hid: Intel-quickspi: Fix non-functional touch
after S3 resume
THC hardware registers lose their content during S3 suspend. Add hardware
reconfiguration on resume from S3 to restore touch functionality.
Signed-off-by: Even Xu <even.xu@intel.com>
---
.../intel-quickspi/pci-quickspi.c | 32 +++++++++++++++++++
.../intel-quickspi/quickspi-dev.h | 4 +++
2 files changed, 36 insertions(+)
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
index 20e8dbf1d313..0d67a0bb2ee7 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -10,6 +10,7 @@
#include <linux/irqreturn.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
#include <linux/gpio/consumer.h>
@@ -765,6 +766,8 @@ static int quickspi_suspend(struct device *device)
thc_dma_unconfigure(qsdev->thc_hw);
+ qsdev->last_suspend_state = pm_suspend_target_state;
+
return 0;
}
@@ -782,6 +785,35 @@ static int quickspi_resume(struct device *device)
if (ret)
return ret;
+ /* If it's resume from S3, need to re-configure SPI port */
+ if (qsdev->last_suspend_state == PM_SUSPEND_MEM) {
+ thc_spi_input_output_address_config(qsdev->thc_hw,
+ qsdev->input_report_hdr_addr,
+ qsdev->input_report_bdy_addr,
+ qsdev->output_report_addr);
+
+ ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val,
+ qsdev->spi_read_io_mode,
+ qsdev->spi_read_opcode,
+ qsdev->spi_packet_size);
+ if (ret)
+ return ret;
+
+ ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val,
+ qsdev->spi_write_io_mode,
+ qsdev->spi_write_opcode,
+ qsdev->spi_packet_size,
+ qsdev->performance_limit);
+ if (ret)
+ return ret;
+
+ thc_ltr_config(qsdev->thc_hw,
+ qsdev->active_ltr_val,
+ qsdev->low_power_ltr_val);
+
+ thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE);
+ }
+
thc_interrupt_config(qsdev->thc_hw);
thc_interrupt_enable(qsdev->thc_hw, true);
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
index ef433fe1b45d..3beeec62dd09 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
@@ -7,6 +7,7 @@
#include <linux/bits.h>
#include <linux/hid-over-spi.h>
#include <linux/sizes.h>
+#include <linux/suspend.h>
#include <linux/wait.h>
#include "quickspi-protocol.h"
@@ -124,6 +125,7 @@ struct acpi_device;
* @get_feature_cmpl: indicate get feature received or not
* @set_feature_cmpl_wq: workqueue for waiting set feature to device
* @set_feature_cmpl: indicate set feature send complete or not
+ * @last_suspend_state: save last system suspend state
*/
struct quickspi_device {
struct device *dev;
@@ -171,6 +173,8 @@ struct quickspi_device {
wait_queue_head_t set_report_cmpl_wq;
bool set_report_cmpl;
+
+ suspend_state_t last_suspend_state;
};
#endif /* _QUICKSPI_DEV_H_ */
--
2.43.0
Sorry, missed the doc link: https://docs.kernel.org/admin-guide/pm/sleep-states.html > -----Original Message----- > From: Xu, Even > Sent: Monday, June 1, 2026 11:25 AM > To: 'd3z-the-dev' <d3z.the.dev@gmail.com>; Sun, Xinpeng > <Xinpeng.Sun@intel.com>; Jiri Kosina <jikos@kernel.org>; Benjamin Tissoires > <bentiss@kernel.org> > Cc: linux-input@vger.kernel.org; linux-kernel@vger.kernel.org; Abhishek Tamboli > <abhishektamboli9@gmail.com>; Sakari Ailus <sakari.ailus@linux.intel.com> > Subject: RE: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on system > resume > > Hi, > > Sorry, I cannot get your exact name from this patch email. > > From your issue description, I suppose Surface Pro 10 uses "Suspend-to-RAM" > instead of "Standby" or "Suspend-to-Idle" for suspend/resume. > As this documents mentioned, driver needs to take care the suspend type then > handle resume flow carefully. > > Actually, I had a patch for this "Suspend-to-RAM" support several months ago, > please find attached file for the patch. This patch is still under our internal final > validation. > > It will be very appreciated if you can help test attached patch on your Surface > device. > If it works, then everything is fine, I will submit this patch with your name after > our final validation. > If it doesn't work for your case, then we need to future debug on your surface > device to refine your patch to let it more standard. > > Thanks! > > Best Regards, > Even Xu > > > -----Original Message----- > > From: d3z-the-dev <d3z.the.dev@gmail.com> > > Sent: Saturday, May 30, 2026 6:22 AM > > To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng > > <xinpeng.sun@intel.com>; Jiri Kosina <jikos@kernel.org>; Benjamin > > Tissoires <bentiss@kernel.org> > > Cc: linux-input@vger.kernel.org; linux-kernel@vger.kernel.org; > > Abhishek Tamboli <abhishektamboli9@gmail.com>; Sakari Ailus > > <sakari.ailus@linux.intel.com>; d3z-the-dev <d3z.the.dev@gmail.com> > > Subject: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on > > system resume > > > > On the Surface Pro 10 (Meteor Lake) the touchscreen stops working > > after a suspend/resume cycle and only recovers after a reboot. The > > driver logs > > "GET_DEVICE_INFO: recv failed: -11" on resume. > > > > The touch IC loses power during system suspend (s2idle) on this > > platform, the same way it does across hibernation. quickspi_resume() > > only restores the THC port, interrupts and DMA and sends a HIDSPI_ON > > command, assuming the touch IC kept its power and state. When it has > > actually lost power the HIDSPI_ON command is never acknowledged and > > the descriptor read fails, leaving the touchscreen dead until the module is > reloaded. > > > > quickspi_restore() already handles this for hibernation by running > > reset_tic() and reconfiguring the THC SPI/LTR settings. Make > > quickspi_resume() do the same: quiesce interrupts, re-select the THC > > port, reconfigure the SPI input/output addresses and read/write > > parameters, run > > reset_tic() to re-enumerate the device and restore the LTR configuration. > > > > Tested on a Surface Pro 10 across multiple s2idle suspend/resume cycles. > > > > Link: https://github.com/linux-surface/linux-surface/issues/1799 > > > > Signed-off-by: d3z-the-dev <d3z.the.dev@gmail.com> > > --- > > .../intel-quickspi/pci-quickspi.c | 38 +++++++++++++++++-- > > 1 file changed, 34 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c > > b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c > > index f669235f1883..d59278a3e5c1 100644 > > --- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c > > +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c > > @@ -780,24 +780,54 @@ static int quickspi_resume(struct device *device) > > if (!qsdev) > > return -ENODEV; > > > > + ret = thc_interrupt_quiesce(qsdev->thc_hw, true); > > + if (ret) > > + return ret; > > + > > ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI); > > if (ret) > > return ret; > > > > + thc_spi_input_output_address_config(qsdev->thc_hw, > > + qsdev->input_report_hdr_addr, > > + qsdev->input_report_bdy_addr, > > + qsdev->output_report_addr); > > + > > + ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val, > > + qsdev->spi_read_io_mode, > > + qsdev->spi_read_opcode, > > + qsdev->spi_packet_size); > > + if (ret) > > + return ret; > > + > > + ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val, > > + qsdev->spi_write_io_mode, > > + qsdev->spi_write_opcode, > > + qsdev->spi_packet_size, > > + qsdev->performance_limit); > > + if (ret) > > + return ret; > > + > > thc_interrupt_config(qsdev->thc_hw); > > > > thc_interrupt_enable(qsdev->thc_hw, true); > > > > - ret = thc_dma_configure(qsdev->thc_hw); > > + /* The TIC may lose power across system suspend, reset it to recover */ > > + ret = reset_tic(qsdev); > > if (ret) > > return ret; > > > > - ret = thc_interrupt_quiesce(qsdev->thc_hw, false); > > + ret = thc_dma_configure(qsdev->thc_hw); > > if (ret) > > return ret; > > > > - if (!device_may_wakeup(qsdev->dev)) > > - return quickspi_set_power(qsdev, HIDSPI_ON); > > + thc_ltr_config(qsdev->thc_hw, > > + qsdev->active_ltr_val, > > + qsdev->low_power_ltr_val); > > + > > + thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE); > > + > > + qsdev->state = QUICKSPI_ENABLED; > > > > return 0; > > } > > -- > > 2.54.0
From: Danny D. <d3z.the.dev@gmail.com>
Hi Even,
Thanks for the quick reply and for sharing your patch.
First, the missing piece from your mail: my name is Danny D.
(d3z.the.dev@gmail.com) - please use it for any
Signed-off-by/Reported-by/Tested-by.
One note on the starting assumption, though: in its current configuration
this Surface Pro 10 doesn't go to S3 at all. /sys/power/mem_sleep only
offers s2idle:
$ cat /sys/power/mem_sleep
[s2idle]
There's no "deep" entry to select here, so every suspend goes through
s2idle and never reaches PM_SUSPEND_MEM. The touch IC still loses power
across that s2idle suspend - the same as over hibernation - which is what
gives the "recv failed: -11" on resume.
That's the catch with the attached patch: it gates the THC reconfigure on
if (last_suspend_state == PM_SUSPEND_MEM)
i.e. S3 only. On this machine that branch never runs, so it wouldn't bring
the touchscreen back here. Happy to apply it and confirm on the device, but
from the code path alone it can't help while we're s2idle-only.
What I did instead was key off whether the device actually kept power
rather than the suspend type: run the full reset only when the device isn't
a wake source (device_may_wakeup() == false), mirroring quickspi_restore().
A wake-enabled device stays on the light path so wake-on-touch is preserved;
one that lost power goes through reset_tic() re-enumeration. That fires on
both s2idle and S3, which is what makes it work on the SP10.
I've tested this on the Surface Pro 10 across many s2idle suspend/resume
cycles - touch and pen both keep working - and just posted a v2 that adds
the device_may_wakeup() gate.
Could we converge on the wakeup-based condition? I'm glad to test any
revision of your patch on the hardware, and equally glad for you to carry
the fix with my Signed-off-by/Tested-by once it handles the s2idle case.
Thanks,
Danny
Hi, Danny, Nice to meet you! Thank you very much for your testing and description detail. According to current situation you described on Surface Pro 10, there are two issues we need to identify separately: 1. Touch IC was powered off According to your description, Touch IC power off can be confirmed. In this case, only reset_tic() call is needed for touch IC recovery. 2. THC was power gated THC power gated is another story, generally speaking, if device doesn't go into PM_SUSPEND_MEM, THC shouldn't be power gated. If so, other API calls to recovery THC state maybe unnecessary. We need to identify this case. So can you help do a test: just only add reset_tic(), to check if touch device can recovery during suspend/resume. Then we can identify if THC was power gated. Thanks! Best Regards, Even Xu > -----Original Message----- > From: d3z <d3z.the.dev@gmail.com> > Sent: Tuesday, June 2, 2026 5:31 AM > To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>; > jikos@kernel.org; bentiss@kernel.org > Cc: Danny D . <d3z.the.dev@gmail.com>; linux-input@vger.kernel.org; linux- > kernel@vger.kernel.org; abhishektamboli9@gmail.com; > sakari.ailus@linux.intel.com > Subject: Re: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on system > resume > > From: Danny D. <d3z.the.dev@gmail.com> > > Hi Even, > > Thanks for the quick reply and for sharing your patch. > > First, the missing piece from your mail: my name is Danny D. > (d3z.the.dev@gmail.com) - please use it for any Signed-off-by/Reported- > by/Tested-by. > > One note on the starting assumption, though: in its current configuration this > Surface Pro 10 doesn't go to S3 at all. /sys/power/mem_sleep only offers s2idle: > > $ cat /sys/power/mem_sleep > [s2idle] > > There's no "deep" entry to select here, so every suspend goes through s2idle and > never reaches PM_SUSPEND_MEM. The touch IC still loses power across that > s2idle suspend - the same as over hibernation - which is what gives the "recv > failed: -11" on resume. > > That's the catch with the attached patch: it gates the THC reconfigure on > > if (last_suspend_state == PM_SUSPEND_MEM) > > i.e. S3 only. On this machine that branch never runs, so it wouldn't bring the > touchscreen back here. Happy to apply it and confirm on the device, but from the > code path alone it can't help while we're s2idle-only. > > What I did instead was key off whether the device actually kept power rather > than the suspend type: run the full reset only when the device isn't a wake source > (device_may_wakeup() == false), mirroring quickspi_restore(). > A wake-enabled device stays on the light path so wake-on-touch is preserved; > one that lost power goes through reset_tic() re-enumeration. That fires on both > s2idle and S3, which is what makes it work on the SP10. > > I've tested this on the Surface Pro 10 across many s2idle suspend/resume cycles - > touch and pen both keep working - and just posted a v2 that adds the > device_may_wakeup() gate. > > Could we converge on the wakeup-based condition? I'm glad to test any revision > of your patch on the hardware, and equally glad for you to carry the fix with my > Signed-off-by/Tested-by once it handles the s2idle case. > > Thanks, > Danny
From: Danny D. <d3z.the.dev@gmail.com>
Hi Even,
Good way to split it - "touch IC off" vs "THC power-gated" - so I ran the
reset_tic()-only test you asked for.
I added just reset_tic() to a pristine quickspi_resume(), with none of the
THC reconfig (no thc_spi_*_config, no thc_ltr_*). On the Surface Pro 10,
after an s2idle suspend/resume, the touchscreen does NOT come back - so
reset_tic() alone isn't enough here.
The interesting bit is why. The one new line on resume is:
intel_quickspi 0000:00:10.0: THC interrupt already unquiesce
That's reset_tic() -> thc_interrupt_quiesce(dev, false) finding
DEVINT_QUIESCE_EN already clear - even though quickspi_suspend() set it in
suspend. thc_regmap is REGCACHE_NONE, so that's the real register, not a
cached value. So the THC port-control state we wrote in suspend is gone
after resume.
That's your second case: the THC itself loses its register context across
s2idle, without ever hitting PM_SUSPEND_MEM. reset_tic()'s SPI exchange
then runs against a THC whose I/O address and read/write config are wiped,
so the reset never completes. Reprogramming those first (like
quickspi_restore(), and like v2 on the no-wake path) is what brings touch
and pen back.
So on the SP10 both are needed - reset the touch IC AND reconfigure the
THC - the full reconfigure looks necessary here.
One note on the log: there's no fresh "Wait RESET_RESPONSE timeout" line
this cycle, but that path is dev_err_once() and the box had ~12h uptime, so
an earlier cycle likely already consumed it.
Thanks,
Danny
Hi, Danny,
Thank you very much!
Very appreciate your testing!
I noticed one thing in your description " there's no fresh 'Wait RESET_RESPONSE timeout' line this cycle ".
Generally, during reset_tic() execution, THC will send/receive data to/from TIC for RESET response, device descriptor.
If there is no any error log after you only add reset_tic() in resume() callback, that means THC isn't power gated, it still keep previous setting and can receive interrupt and response interrupt correctly.
Suddenly, I recognized, reset_tic() will set device state to RESETTING:
qsdev->state = QUICKSPI_RESETING;
So after reset_tic() call, driver must manually set device state to ENABLE:
qsdev->state = QUICKSPI_ENABLED;
If no this setting, THC hardware works normally, but driver will ignore all input data, the phenomenon is that the touch screen still has no response.
That's my bad, I forgot this.
So would you mind try again, to add the missed line, like this:
--- i/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ w/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -822,10 +822,17 @@ static int quickspi_resume(struct device *device)
if (ret)
return ret;
+ /* TIC may lose power, needs go through reset flow */
+ ret = reset_tic(qsdev);
+ if (ret)
+ return ret;
+
ret = thc_interrupt_quiesce(qsdev->thc_hw, false);
if (ret)
return ret;
+ qsdev->state = QUICKSPI_ENABLED;
+
if (!device_may_wakeup(qsdev->dev))
return quickspi_set_power(qsdev, HIDSPI_ON);
Thanks!
Best Regards,
Even Xu
> -----Original Message-----
> From: d3z <d3z.the.dev@gmail.com>
> Sent: Tuesday, June 2, 2026 11:13 PM
> To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>;
> jikos@kernel.org; bentiss@kernel.org
> Cc: Danny D . <d3z.the.dev@gmail.com>; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org; abhishektamboli9@gmail.com;
> sakari.ailus@linux.intel.com
> Subject: Re: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on system
> resume
>
> From: Danny D. <d3z.the.dev@gmail.com>
>
> Hi Even,
>
> Good way to split it - "touch IC off" vs "THC power-gated" - so I ran the
> reset_tic()-only test you asked for.
>
> I added just reset_tic() to a pristine quickspi_resume(), with none of the THC
> reconfig (no thc_spi_*_config, no thc_ltr_*). On the Surface Pro 10, after an
> s2idle suspend/resume, the touchscreen does NOT come back - so
> reset_tic() alone isn't enough here.
>
> The interesting bit is why. The one new line on resume is:
>
> intel_quickspi 0000:00:10.0: THC interrupt already unquiesce
>
> That's reset_tic() -> thc_interrupt_quiesce(dev, false) finding
> DEVINT_QUIESCE_EN already clear - even though quickspi_suspend() set it in
> suspend. thc_regmap is REGCACHE_NONE, so that's the real register, not a
> cached value. So the THC port-control state we wrote in suspend is gone after
> resume.
>
> That's your second case: the THC itself loses its register context across s2idle,
> without ever hitting PM_SUSPEND_MEM. reset_tic()'s SPI exchange then runs
> against a THC whose I/O address and read/write config are wiped, so the reset
> never completes. Reprogramming those first (like quickspi_restore(), and like v2
> on the no-wake path) is what brings touch and pen back.
>
> So on the SP10 both are needed - reset the touch IC AND reconfigure the THC -
> the full reconfigure looks necessary here.
>
> One note on the log: there's no fresh "Wait RESET_RESPONSE timeout" line this
> cycle, but that path is dev_err_once() and the box had ~12h uptime, so an earlier
> cycle likely already consumed it.
>
> Thanks,
> Danny
From: Danny D. <d3z.the.dev@gmail.com>
Hi Even,
Good catch on the missing state restore. I rebuilt with your version and
re-ran the test.
This is exactly your proposal: reset_tic() after thc_dma_configure(),
then qsdev->state = QUICKSPI_ENABLED, with no thc_spi_*_config and no
thc_ltr_*. I built it as a module and swapped it into a clean
linux-surface 6.19.8 on the Surface Pro 10.
It still doesn't survive s2idle - touch is fine at probe, but after one
suspend/resume it's dead again. This time resume() fails outright instead
of coming back quietly broken:
intel_quickspi 0000:00:10.0: Wait DEVICE_DESCRIPTOR timeout, ret:0
intel_quickspi 0000:00:10.0: PM: dpm_run_callback(): pci_pm_resume returns -110
intel_quickspi 0000:00:10.0: PM: failed to resume async: error -110
So reset_tic() can't complete here. It clears the reset handshake, then
times out in quickspi_get_device_descriptor() and the whole resume bails
with -ETIMEDOUT. The device isn't a wake source on this box - "Can't find
wake GPIO resource" - so device_may_wakeup() is false and we're on the
reset path, as expected.
And the timeout is the THC, not the touch IC: across s2idle its SPI
input/output address and read/write config are gone, so reset_tic()'s
descriptor exchange has nothing valid to run against. Reprogram those
first - the thc_spi_input_output_address_config + read_config +
write_config block, same as quickspi_restore(), same as v2 on the no-wake
path - and reset_tic() completes and touch comes back. That's exactly why
v2 reconfigures the THC instead of only resetting the IC.
One more platform note: the SP10 never reaches S3. Firmware only offers
s2idle - mem_sleep is just "[s2idle]", with no "deep" entry to select -
yet the THC still loses its context across plain s2idle. So a reset gated
on S3 would never fire here, which is why it has to run on the ordinary
resume path.
Thanks,
Danny
Hi, Danny, Thanks for your patient to have some many tries. According to above tests, it seems Surface Pro 10 does not only power off the TIC but also the THC for suspend. Then your patch is need for this case. I will add my review flag for your patch, thanks for your attribution! Best Regards, Even Xu > -----Original Message----- > From: d3z <d3z.the.dev@gmail.com> > Sent: Friday, June 5, 2026 4:27 AM > To: Xu, Even <even.xu@intel.com>; Sun, Xinpeng <xinpeng.sun@intel.com>; > jikos@kernel.org; bentiss@kernel.org > Cc: Danny D . <d3z.the.dev@gmail.com>; linux-input@vger.kernel.org; linux- > kernel@vger.kernel.org; abhishektamboli9@gmail.com; > sakari.ailus@linux.intel.com > Subject: Re: [PATCH] HID: intel-thc-hid: intel-quickspi: reset touch IC on system > resume > > From: Danny D. <d3z.the.dev@gmail.com> > > Hi Even, > > Good catch on the missing state restore. I rebuilt with your version and re-ran the > test. > > This is exactly your proposal: reset_tic() after thc_dma_configure(), then qsdev- > >state = QUICKSPI_ENABLED, with no thc_spi_*_config and no thc_ltr_*. I built it > as a module and swapped it into a clean linux-surface 6.19.8 on the Surface Pro > 10. > > It still doesn't survive s2idle - touch is fine at probe, but after one > suspend/resume it's dead again. This time resume() fails outright instead of > coming back quietly broken: > > intel_quickspi 0000:00:10.0: Wait DEVICE_DESCRIPTOR timeout, ret:0 > intel_quickspi 0000:00:10.0: PM: dpm_run_callback(): pci_pm_resume returns > -110 > intel_quickspi 0000:00:10.0: PM: failed to resume async: error -110 > > So reset_tic() can't complete here. It clears the reset handshake, then times out > in quickspi_get_device_descriptor() and the whole resume bails with - > ETIMEDOUT. The device isn't a wake source on this box - "Can't find wake GPIO > resource" - so device_may_wakeup() is false and we're on the reset path, as > expected. > > And the timeout is the THC, not the touch IC: across s2idle its SPI input/output > address and read/write config are gone, so reset_tic()'s descriptor exchange has > nothing valid to run against. Reprogram those first - the > thc_spi_input_output_address_config + read_config + write_config block, same > as quickspi_restore(), same as v2 on the no-wake path - and reset_tic() completes > and touch comes back. That's exactly why > v2 reconfigures the THC instead of only resetting the IC. > > One more platform note: the SP10 never reaches S3. Firmware only offers s2idle - > mem_sleep is just "[s2idle]", with no "deep" entry to select - yet the THC still > loses its context across plain s2idle. So a reset gated on S3 would never fire here, > which is why it has to run on the ordinary resume path. > > Thanks, > Danny
© 2016 - 2026 Red Hat, Inc.