From f424a8fe6753599c9f5827b0e323f57bf20bdee0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 14 Dec 2023 18:39:31 +0000 Subject: [PATCH 1/9] mei: fix vsc dependency mainline inclusion from mainline-v6.8-rc1 category: bugfix CONFIG_INTEL_MEI_VSC_HW can be set to built-in even with CONFIG_MEI=m, but then the driver is not built because Kbuild never enters the drivers/misc/mei directory for built-in files, leading to a link failure: ERROR: modpost: "vsc_tp_reset" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_init" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_xfer" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_need_read" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_intr_enable" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_intr_synchronize" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_intr_disable" [drivers/misc/mei/mei-vsc.ko] undefined! ERROR: modpost: "vsc_tp_register_event_cb" [drivers/misc/mei/mei-vsc.ko] undefined! Add an explicit dependency on CONFIG_MEI that was apparently missing, to ensure the VSC_HW driver cannot be built-in with MEI itself being a loadable module. Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Signed-off-by: Arnd Bergmann Reviewed-by: Sakari Ailus Reviewed-by: Wentong Wu Link: https://lore.kernel.org/r/20231214183946.109124-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 95171e45663307fc33a939f0220b39afadfe7cb9) Signed-off-by: Wentao Guan --- drivers/misc/mei/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index 858bd701d68c3..1e28ca23a74ad 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -62,6 +62,7 @@ config INTEL_MEI_GSC config INTEL_MEI_VSC_HW tristate "Intel visual sensing controller device transport driver" + depends on INTEL_MEI depends on ACPI && SPI depends on GPIOLIB || COMPILE_TEST help From 176e57207126ff235de5cfda842a86a029315770 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Feb 2025 22:24:25 +0100 Subject: [PATCH 2/9] mei: vsc: Use "wakeuphostint" when getting the host wakeup GPIO mainline inclusion from mainline-v6.14-rc6 category: bugfix The _CRS ACPI resources table has 2 entries for the host wakeup GPIO, the first one being a regular GpioIo () resource while the second one is a GpioInt () resource for the same pin. The acpi_gpio_mapping table used by vsc-tp.c maps the first Gpio () resource to "wakeuphost-gpios" where as the second GpioInt () entry is mapped to "wakeuphostint-gpios". Using "wakeuphost" to request the GPIO as was done until now, means that the gpiolib-acpi code does not know that the GPIO is active-low as that info is only available in the GpioInt () entry. Things were still working before due to the following happening: 1. Since the 2 entries point to the same pin they share a struct gpio_desc 2. The SPI core creates the SPI device vsc-tp.c binds to and calls acpi_dev_gpio_irq_get(). This does use the second entry and sets FLAG_ACTIVE_LOW in gpio_desc.flags . 3. vsc_tp_probe() requests the "wakeuphost" GPIO and inherits the active-low flag set by acpi_dev_gpio_irq_get() But there is a possible scenario where things do not work: 1. - 3. happen as above 4. After requesting the "wakeuphost" GPIO, the "resetfw" GPIO is requested next, but its USB GPIO controller is not available yet, so this call returns -EPROBE_DEFER. 5. The gpio_desc for "wakeuphost" is put() and during this the active-low flag is cleared from gpio_desc.flags . 6. Later on vsc_tp_probe() requests the "wakeuphost" GPIO again, but now it is not marked active-low. The difference can also be seen in /sys/kernel/debug/gpio, which contains the following line for this GPIO: gpio-535 ( |wakeuphost ) in hi IRQ ACTIVE LOW If the second scenario is hit the "ACTIVE LOW" at the end disappears and things do not work. Fix this by requesting the GPIO through the "wakeuphostint" mapping instead which provides active-low info without relying on acpi_dev_gpio_irq_get() pre-populating this info in the gpio_desc. Link: https://bugzilla.redhat.com/show_bug.cgi?id=2316918 Signed-off-by: Hans de Goede Reviewed-by: Stanislaw Gruszka Tested-by: Sakari Ailus Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Cc: stable Link: https://lore.kernel.org/r/20250214212425.84021-1-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit fdb1ada57cf8b8752cdf54f08709d76d74999544) Signed-off-by: Wentao Guan --- drivers/misc/mei/vsc-tp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index e6a98dba8a735..f7d96c117d683 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -504,7 +504,7 @@ static int vsc_tp_probe(struct spi_device *spi) if (ret) return ret; - tp->wakeuphost = devm_gpiod_get(dev, "wakeuphost", GPIOD_IN); + tp->wakeuphost = devm_gpiod_get(dev, "wakeuphostint", GPIOD_IN); if (IS_ERR(tp->wakeuphost)) return PTR_ERR(tp->wakeuphost); From 9294100ed9d509135de8ce983817c288cab276e7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 6 Nov 2024 23:01:02 +0100 Subject: [PATCH 3/9] mei: vsc: Do not re-enable interrupt from vsc_tp_reset() mainline inclusion from mainline-v6.13-rc1 category: bugfix The only 2 callers of vsc_tp_reset() are: 1. mei_vsc_hw_reset(), which immediataly calls vsc_tp_intr_disable() afterwards. 2. vsc_tp_shutdown() which immediately calls free_irq() afterwards. So neither actually wants the interrupt to be enabled after resetting the chip and having the interrupt enabled for a short time afer the reset is undesirable. Drop the enable_irq() call from vsc_tp_reset(), so that the interrupt is left disabled after vsc_tp_reset(). Link: https://github.com/intel/ivsc-driver/issues/51 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20241106220102.40549-1-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 49988a7975420eb206c783f8a384458aae85d938) Signed-off-by: Wentao Guan --- drivers/misc/mei/platform-vsc.c | 2 -- drivers/misc/mei/vsc-tp.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c index b543e6b9f3cfd..38f8951f759ea 100644 --- a/drivers/misc/mei/platform-vsc.c +++ b/drivers/misc/mei/platform-vsc.c @@ -256,8 +256,6 @@ static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable) vsc_tp_reset(hw->tp); - vsc_tp_intr_disable(hw->tp); - return vsc_tp_init(hw->tp, mei_dev->dev); } diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index f7d96c117d683..857a70f7f2219 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -364,8 +364,6 @@ void vsc_tp_reset(struct vsc_tp *tp) gpiod_set_value_cansleep(tp->wakeupfw, 1); atomic_set(&tp->assert_cnt, 0); - - enable_irq(tp->spi->irq); } EXPORT_SYMBOL_NS_GPL(vsc_tp_reset, VSC_TP); From 0503237d3815ff381ae3e1529cd704fd45dfbf11 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:44 +0200 Subject: [PATCH 4/9] mei: vsc: Don't re-init VSC from mei_vsc_hw_reset() on stop mainline inclusion from mainline-v6.17-rc1 category: bugfix mei_vsc_hw_reset() gets called from mei_start() and mei_stop() in the latter case we do not need to re-init the VSC by calling vsc_tp_init(). mei_stop() only happens on shutdown and driver unbind. On shutdown we don't need to load + boot the firmware and if the driver later is bound to the device again then mei_start() will do another reset. The intr_enable flag is true when called from mei_start() and false on mei_stop(). Skip vsc_tp_init() when intr_enable is false. This avoids unnecessarily uploading the firmware, which takes 11 seconds. This change reduces the poweroff/reboot time by 11 seconds. Fixes: 386a766c4169 ("mei: Add MEI hardware support for IVSC device") Signed-off-by: Hans de Goede Reviewed-by: Alexander Usyskin Link: https://lore.kernel.org/r/20250623085052.12347-3-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 880af854d6343b796f05b9a8b52b68a88535625b) Signed-off-by: Wentao Guan --- drivers/misc/mei/platform-vsc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c index 38f8951f759ea..9a1f71ab7748e 100644 --- a/drivers/misc/mei/platform-vsc.c +++ b/drivers/misc/mei/platform-vsc.c @@ -256,6 +256,9 @@ static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable) vsc_tp_reset(hw->tp); + if (!intr_enable) + return 0; + return vsc_tp_init(hw->tp, mei_dev->dev); } From 1aa7468989e342efcef06df69a0dfd0dc564e131 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:47 +0200 Subject: [PATCH 5/9] mei: vsc: Destroy mutex after freeing the IRQ mainline inclusion from mainline-v6.17-rc1 category: bugfix The event_notify callback which runs from vsc_tp_thread_isr may call vsc_tp_xfer() which locks the mutex. So the ISR depends on the mutex. Move the mutex_destroy() call to after free_irq() to ensure that the ISR is not running while the mutex is destroyed. Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250623085052.12347-6-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 35b7f3525fe0a7283de7116e3c75ee3ccb3b14c9) Signed-off-by: Wentao Guan --- drivers/misc/mei/vsc-tp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 857a70f7f2219..05a05ceb4314e 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -548,10 +548,10 @@ static int vsc_tp_probe(struct spi_device *spi) return 0; err_destroy_lock: - mutex_destroy(&tp->mutex); - free_irq(spi->irq, tp); + mutex_destroy(&tp->mutex); + return ret; } @@ -561,9 +561,9 @@ static void vsc_tp_remove(struct spi_device *spi) platform_device_unregister(tp->pdev); - mutex_destroy(&tp->mutex); - free_irq(spi->irq, tp); + + mutex_destroy(&tp->mutex); } static const struct acpi_device_id vsc_tp_acpi_ids[] = { From e1fb824da8c3ee2ea8d4549372c7f5965b1ecacd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:48 +0200 Subject: [PATCH 6/9] mei: vsc: Event notifier fixes mainline inclusion from mainline-v6.17-rc1 category: bugfix vsc_tp_register_event_cb() can race with vsc_tp_thread_isr(), add a mutex to protect against this. Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250623085052.12347-7-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 18f14b2e7f73c7ec272d833d570b632286467c7d) Signed-off-by: Wentao Guan --- drivers/misc/mei/vsc-tp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 05a05ceb4314e..b10d9d95043ce 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -75,9 +75,8 @@ struct vsc_tp { vsc_tp_event_cb_t event_notify; void *event_notify_context; - - /* used to protect command download */ - struct mutex mutex; + struct mutex event_notify_mutex; /* protects event_notify + context */ + struct mutex mutex; /* protects command download */ }; /* GPIO resources */ @@ -109,6 +108,8 @@ static irqreturn_t vsc_tp_thread_isr(int irq, void *data) { struct vsc_tp *tp = data; + guard(mutex)(&tp->event_notify_mutex); + if (tp->event_notify) tp->event_notify(tp->event_notify_context); @@ -395,6 +396,8 @@ EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, VSC_TP); int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb, void *context) { + guard(mutex)(&tp->event_notify_mutex); + tp->event_notify = event_cb; tp->event_notify_context = context; @@ -526,6 +529,7 @@ static int vsc_tp_probe(struct spi_device *spi) return ret; mutex_init(&tp->mutex); + mutex_init(&tp->event_notify_mutex); /* only one child acpi device */ ret = acpi_dev_for_each_child(ACPI_COMPANION(dev), @@ -550,6 +554,7 @@ static int vsc_tp_probe(struct spi_device *spi) err_destroy_lock: free_irq(spi->irq, tp); + mutex_destroy(&tp->event_notify_mutex); mutex_destroy(&tp->mutex); return ret; @@ -563,6 +568,7 @@ static void vsc_tp_remove(struct spi_device *spi) free_irq(spi->irq, tp); + mutex_destroy(&tp->event_notify_mutex); mutex_destroy(&tp->mutex); } From 997e81ef6f63b2e9f44ea555678c3f195694666d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:49 +0200 Subject: [PATCH 7/9] mei: vsc: Unset the event callback on remove and probe errors mainline inclusion from mainline-v6.17-rc1 category: bugfix Make mei_vsc_remove() properly unset the callback to avoid a dead callback sticking around after probe errors or unbinding of the platform driver. Fixes: 386a766c4169 ("mei: Add MEI hardware support for IVSC device") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250623085052.12347-8-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 6175c6974095f8ca7e5f8d593171512f3e5bd453) Signed-off-by: Wentao Guan --- drivers/misc/mei/platform-vsc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c index 9a1f71ab7748e..f2bde72613b1a 100644 --- a/drivers/misc/mei/platform-vsc.c +++ b/drivers/misc/mei/platform-vsc.c @@ -380,6 +380,8 @@ static int mei_vsc_probe(struct platform_device *pdev) err_cancel: mei_cancel_work(mei_dev); + vsc_tp_register_event_cb(tp, NULL, NULL); + mei_disable_interrupts(mei_dev); return ret; @@ -388,11 +390,14 @@ static int mei_vsc_probe(struct platform_device *pdev) static void mei_vsc_remove(struct platform_device *pdev) { struct mei_device *mei_dev = platform_get_drvdata(pdev); + struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev); pm_runtime_disable(mei_dev->dev); mei_stop(mei_dev); + vsc_tp_register_event_cb(hw->tp, NULL, NULL); + mei_disable_interrupts(mei_dev); mei_deregister(mei_dev); From cdfb939368f7054dd8987c2fb5b97726ac4a8a87 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:50 +0200 Subject: [PATCH 8/9] mei: vsc: Run event callback from a workqueue mainline inclusion from mainline-v6.17-rc1 category: bugfix The event_notify callback in some cases calls vsc_tp_xfer(), which checks tp->assert_cnt and waits for it through the tp->xfer_wait wait-queue. And tp->assert_cnt is increased and the tp->xfer_wait queue is woken o from the interrupt handler. So the interrupt handler which is running the event callback is waiting for itself to signal that it can continue. This happens to work because the event callback runs from the threaded ISR handler and while that is running the hard ISR handler will still get called a second / third time for further interrupts and it is the hard ISR handler which does the atomic_inc() and wake_up() calls. But having the threaded ISR handler wait for its own interrupt to trigger again is not how a threaded ISR handler is supposed to be used. Move the running of the event callback from a threaded interrupt handler to a workqueue since a threaded ISR should not wait for events from its own interrupt. This is a preparation patch for moving the atomic_inc() and wake_up() calls to the threaded ISR handler, which is necessary to fix a locking issue. Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250623085052.12347-9-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit de88b02c94db7f3c115eb5bfdc1ec444934f277a) Signed-off-by: Wentao Guan --- drivers/misc/mei/vsc-tp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index b10d9d95043ce..55463baabe983 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "vsc-tp.h" @@ -72,6 +73,7 @@ struct vsc_tp { atomic_t assert_cnt; wait_queue_head_t xfer_wait; + struct work_struct event_work; vsc_tp_event_cb_t event_notify; void *event_notify_context; @@ -101,19 +103,19 @@ static irqreturn_t vsc_tp_isr(int irq, void *data) wake_up(&tp->xfer_wait); - return IRQ_WAKE_THREAD; + schedule_work(&tp->event_work); + + return IRQ_HANDLED; } -static irqreturn_t vsc_tp_thread_isr(int irq, void *data) +static void vsc_tp_event_work(struct work_struct *work) { - struct vsc_tp *tp = data; + struct vsc_tp *tp = container_of(work, struct vsc_tp, event_work); guard(mutex)(&tp->event_notify_mutex); if (tp->event_notify) tp->event_notify(tp->event_notify_context); - - return IRQ_HANDLED; } /* wakeup firmware and wait for response */ @@ -522,7 +524,7 @@ static int vsc_tp_probe(struct spi_device *spi) tp->spi = spi; irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY); - ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr, + ret = request_threaded_irq(spi->irq, vsc_tp_isr, NULL, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), tp); if (ret) @@ -530,6 +532,7 @@ static int vsc_tp_probe(struct spi_device *spi) mutex_init(&tp->mutex); mutex_init(&tp->event_notify_mutex); + INIT_WORK(&tp->event_work, vsc_tp_event_work); /* only one child acpi device */ ret = acpi_dev_for_each_child(ACPI_COMPANION(dev), @@ -554,6 +557,7 @@ static int vsc_tp_probe(struct spi_device *spi) err_destroy_lock: free_irq(spi->irq, tp); + cancel_work_sync(&tp->event_work); mutex_destroy(&tp->event_notify_mutex); mutex_destroy(&tp->mutex); @@ -568,6 +572,7 @@ static void vsc_tp_remove(struct spi_device *spi) free_irq(spi->irq, tp); + cancel_work_sync(&tp->event_work); mutex_destroy(&tp->event_notify_mutex); mutex_destroy(&tp->mutex); } From 3e3da291818252a2ba80ff53f5657c1dad21b35e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2025 10:50:51 +0200 Subject: [PATCH 9/9] mei: vsc: Fix "BUG: Invalid wait context" lockdep error mainline inclusion from mainline-v6.17-rc1 category: bugfix Kernels build with CONFIG_PROVE_RAW_LOCK_NESTING report the following tp-vsc lockdep error: ============================= [ BUG: Invalid wait context ] ... swapper/10/0 is trying to lock: ffff88819c271888 (&tp->xfer_wait){....}-{3:3}, at: __wake_up (kernel/sched/wait.c:106 kernel/sched/wait.c:127) ... Call Trace: ... __raw_spin_lock_irqsave (./include/linux/spinlock_api_smp.h:111) __wake_up (kernel/sched/wait.c:106 kernel/sched/wait.c:127) vsc_tp_isr (drivers/misc/mei/vsc-tp.c:110) mei_vsc_hw __handle_irq_event_percpu (kernel/irq/handle.c:158) handle_irq_event (kernel/irq/handle.c:195 kernel/irq/handle.c:210) handle_edge_irq (kernel/irq/chip.c:833) ... The root-cause of this is the IRQF_NO_THREAD flag used by the intel-pinctrl code. Setting IRQF_NO_THREAD requires all interrupt handlers for GPIO ISRs to use raw-spinlocks only since normal spinlocks can sleep in PREEMPT-RT kernels and with IRQF_NO_THREAD the interrupt handlers will always run in an atomic context [1]. vsc_tp_isr() calls wake_up(&tp->xfer_wait), which uses a regular spinlock, breaking the raw-spinlocks only rule for Intel GPIO ISRs. Make vsc_tp_isr() run as threaded ISR instead of as hard ISR to fix this. Fixes: 566f5ca97680 ("mei: Add transport driver for IVSC device") Link: https://lore.kernel.org/linux-gpio/18ab52bd-9171-4667-a600-0f52ab7017ac@kernel.org/ [1] Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250623085052.12347-10-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman (cherry picked from commit cee3dba7b7416c02ff3cd27489f82859cc852532) Signed-off-by: Wentao Guan --- drivers/misc/mei/vsc-tp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 55463baabe983..caacff61f9015 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -524,7 +524,7 @@ static int vsc_tp_probe(struct spi_device *spi) tp->spi = spi; irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY); - ret = request_threaded_irq(spi->irq, vsc_tp_isr, NULL, + ret = request_threaded_irq(spi->irq, NULL, vsc_tp_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), tp); if (ret)