* [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources
@ 2026-10-19 23:44 Myeonghun Pak
2026-10-19 23:53 ` sashiko-bot
2026-10-20 0:37 ` Guenter Roeck
0 siblings, 2 replies; 4+ messages in thread
From: Myeonghun Pak @ 2026-10-19 23:44 UTC (permalink / raw)
To: Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Ijae Kim
The IRQ handler can queue read_work, which accesses GPIOs and may re-enable
that same IRQ. A measurement can return while read_work is still pending
or running. The regulator notifier can also queue update_supply_work,
which accesses the regulator. Neither work item was drained on removal
or on all probe failure paths before the managed resources were released.
Use request_irq() and free_irq() since the IRQ must be released at an
explicit point in the teardown sequence. Disable and drain read_work
before freeing the IRQ. Unregister the regulator notifier before draining
update_supply_work and disabling the regulator.
Use IRQF_NO_AUTOEN to ensure that the IRQ stays disabled until the first
measurement, rather than enabling it briefly between request_irq() and
disable_irq_nosync(). Cache the IRQ number and check errors from
gpiod_to_irq().
Fixes: 251eb40f5ccd ("hwmon: sht15 humidity sensor driver")
Assisted-by: LLM
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
Compile-tested (W=1). No runtime testing.
Changes in v2:
- Replace managed IRQ request/free with request_irq()/free_irq().
- Use IRQF_NO_AUTOEN and cache the data GPIO IRQ.
- Preserve asynchronous work drain ordering on probe failure and remove.
drivers/hwmon/sht15.c | 47 +++++++++++++++++++++++++++++++++--------------
1 file changed, 33 insertions(+), 14 deletions(-)
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 7bb2105d1ae223e7131ba4cc0523e4e074e01302..c95acec7ae2f8f57a10bd72f65a2905e64c3c58c 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -31,6 +31,7 @@
#include <linux/bitrev.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
+#include <linux/workqueue.h>
/* Commands */
#define SHT15_MEASURE_TEMP 0x03
@@ -120,6 +121,7 @@ static const u8 sht15_crc8_table[] = {
* struct sht15_data - device instance specific data
* @sck: clock GPIO line
* @data: data GPIO line
+ * @irq: interrupt number for the data GPIO line.
* @read_work: bh of interrupt handler.
* @wait_queue: wait queue for getting values from device.
* @val_temp: last temperature value read from device.
@@ -149,6 +151,7 @@ static const u8 sht15_crc8_table[] = {
struct sht15_data {
struct gpio_desc *sck;
struct gpio_desc *data;
+ int irq;
struct work_struct read_work;
wait_queue_head_t wait_queue;
uint16_t val_temp;
@@ -532,9 +535,9 @@ static int sht15_measurement(struct sht15_data *data,
return ret;
atomic_set(&data->interrupt_handled, 0);
- enable_irq(gpiod_to_irq(data->data));
+ enable_irq(data->irq);
if (gpiod_get_value(data->data) == 0) {
- disable_irq_nosync(gpiod_to_irq(data->data));
+ disable_irq_nosync(data->irq);
/* Only relevant if the interrupt hasn't occurred. */
if (!atomic_read(&data->interrupt_handled))
schedule_work(&data->read_work);
@@ -546,7 +549,7 @@ static int sht15_measurement(struct sht15_data *data,
data->state = SHT15_READING_NOTHING;
return -EIO;
} else if (ret == 0) { /* timeout occurred */
- disable_irq_nosync(gpiod_to_irq(data->data));
+ disable_irq_nosync(data->irq);
ret = sht15_connection_reset(data);
if (ret)
return ret;
@@ -825,7 +828,7 @@ static void sht15_bh_read_data(struct work_struct *work_s)
* have gone low in meantime so verify it hasn't!
*/
atomic_set(&data->interrupt_handled, 0);
- enable_irq(gpiod_to_irq(data->data));
+ enable_irq(data->irq);
/* If still not occurred or another handler was scheduled */
if (gpiod_get_value(data->data)
|| atomic_read(&data->interrupt_handled))
@@ -976,25 +979,31 @@ static int sht15_probe(struct platform_device *pdev)
goto err_release_reg;
}
- ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
- sht15_interrupt_fired,
- IRQF_TRIGGER_FALLING,
- "sht15 data",
- data);
- if (ret)
+ data->irq = gpiod_to_irq(data->data);
+ if (data->irq < 0) {
+ ret = data->irq;
+ goto err_release_reg;
+ }
+
+ ret = request_irq(data->irq, sht15_interrupt_fired,
+ IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
+ "sht15 data", data);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get irq for data line\n");
goto err_release_reg;
- disable_irq_nosync(gpiod_to_irq(data->data));
+ }
+ /* IRQ remains disabled until a measurement starts. */
ret = sht15_connection_reset(data);
if (ret)
- goto err_release_reg;
+ goto err_free_irq;
ret = sht15_soft_reset(data);
if (ret)
- goto err_release_reg;
+ goto err_free_irq;
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");
- goto err_release_reg;
+ goto err_free_irq;
}
data->hwmon_dev = hwmon_device_register(data->dev);
@@ -1007,9 +1016,14 @@ static int sht15_probe(struct platform_device *pdev)
err_release_sysfs_group:
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
+err_free_irq:
+ /* The read worker can re-enable the IRQ, so drain it first. */
+ disable_work_sync(&data->read_work);
+ free_irq(data->irq, data);
err_release_reg:
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
+ cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
return ret;
@@ -1023,12 +1037,17 @@ static void sht15_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
+ /* The worker can re-enable the IRQ, so stop it before free_irq(). */
+ disable_work_sync(&data->read_work);
+ free_irq(data->irq, data);
+
ret = sht15_soft_reset(data);
if (ret)
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
+ cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources
2026-10-19 23:44 [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources Myeonghun Pak
@ 2026-10-19 23:53 ` sashiko-bot
2026-10-20 0:37 ` Guenter Roeck
1 sibling, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-10-19 23:53 UTC (permalink / raw)
To: Myeonghun Pak; +Cc: linux-hwmon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] hwmon: (sht15) IRQF_NO_AUTOEN in sht15_probe() breaks gpiod_direction_output()
--
commit 0765de729006e4101f713c8613f8a3c9ed6e7d2e
Author: Myeonghun Pak <mhun512@gmail.com>
hwmon: (sht15) Stop deferred work before releasing its resources
This commit switches the SHT15 driver from devm_request_irq() to
request_irq() and free_irq(), adds IRQF_NO_AUTOEN, and drains
read_work and update_supply_work during probe failure and device removal.
> diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
> index 7bb2105d1ae22..c95acec7ae2f8 100644
> --- a/drivers/hwmon/sht15.c
> +++ b/drivers/hwmon/sht15.c
[ ... ]
> @@ -976,25 +979,31 @@ static int sht15_probe(struct platform_device *pdev)
> goto err_release_reg;
> }
>
> - ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
> - sht15_interrupt_fired,
> - IRQF_TRIGGER_FALLING,
> - "sht15 data",
> - data);
> - if (ret)
> + data->irq = gpiod_to_irq(data->data);
> + if (data->irq < 0) {
> + ret = data->irq;
> + goto err_release_reg;
> + }
> +
> + ret = request_irq(data->irq, sht15_interrupt_fired,
> + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
> + "sht15 data", data);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to get irq for data line\n");
> goto err_release_reg;
> - disable_irq_nosync(gpiod_to_irq(data->data));
> + }
> + /* IRQ remains disabled until a measurement starts. */
> ret = sht15_connection_reset(data);
> if (ret)
> - goto err_release_reg;
> + goto err_free_irq;
[Severity: High]
Does replacing disable_irq_nosync() with IRQF_NO_AUTOEN cause
sht15_connection_reset() to fail with -EIO on probe?
During request_irq(), __setup_irq() activates the IRQ and invokes
gpiochip_lock_as_irq() in drivers/gpio/gpiolib.c, which unconditionally sets
both GPIOD_FLAG_USED_AS_IRQ and GPIOD_FLAG_IRQ_IS_ENABLED on data->data:
drivers/gpio/gpiolib.c:gpiochip_lock_as_irq() {
...
set_bit(GPIOD_FLAG_USED_AS_IRQ, &desc->flags);
set_bit(GPIOD_FLAG_IRQ_IS_ENABLED, &desc->flags);
...
}
When IRQF_NO_AUTOEN is passed, __setup_irq() in kernel/irq/manage.c skips
irq_startup() and only sets desc->depth = 1 without calling irq_disable() or
gpiochip_disable_irq():
kernel/irq/manage.c:__setup_irq() {
...
if (!(new->flags & IRQF_NO_AUTOEN) &&
irq_settings_can_autoenable(desc)) {
irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
} else if (!per_cpu_devid) {
WARN_ON_ONCE(new->flags & IRQF_SHARED);
/* Undo nested disables: */
desc->depth = 1;
}
...
}
Previously, calling disable_irq_nosync() after requesting the IRQ invoked
irq_disable() -> gpiochip_disable_irq(), which cleared
GPIOD_FLAG_IRQ_IS_ENABLED. With IRQF_NO_AUTOEN, GPIOD_FLAG_IRQ_IS_ENABLED
remains set when sht15_connection_reset() calls
gpiod_direction_output(data->data, 1):
drivers/gpio/gpiolib.c:gpiod_direction_output_nonotify() {
...
/* GPIOs used for enabled IRQs shall not be set as output */
if (test_bit(GPIOD_FLAG_USED_AS_IRQ, &flags) &&
test_bit(GPIOD_FLAG_IRQ_IS_ENABLED, &flags)) {
gpiod_err(desc,
"%s: tried to set a GPIO tied to an IRQ as output\n",
__func__);
return -EIO;
}
...
}
Will this cause gpiod_direction_output() in sht15_connection_reset() (and in
sht15_transmission_start() before the first enable_irq()) to return -EIO
whenever data->data is backed by a gpiolib irqchip?
[ ... ]
ওয়াট
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019234402.805759-1-mhun512@gmail.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources
2026-10-19 23:44 [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources Myeonghun Pak
2026-10-19 23:53 ` sashiko-bot
@ 2026-10-20 0:37 ` Guenter Roeck
2026-10-20 23:37 ` Myeonghun Pak
1 sibling, 1 reply; 4+ messages in thread
From: Guenter Roeck @ 2026-10-20 0:37 UTC (permalink / raw)
To: Myeonghun Pak; +Cc: linux-hwmon, linux-kernel, Ijae Kim
On 10/19/26 16:44, Myeonghun Pak wrote:
> The IRQ handler can queue read_work, which accesses GPIOs and may re-enable
> that same IRQ. A measurement can return while read_work is still pending
> or running. The regulator notifier can also queue update_supply_work,
> which accesses the regulator. Neither work item was drained on removal
> or on all probe failure paths before the managed resources were released.
>
> Use request_irq() and free_irq() since the IRQ must be released at an
> explicit point in the teardown sequence. Disable and drain read_work
> before freeing the IRQ. Unregister the regulator notifier before draining
> update_supply_work and disabling the regulator.
>
> Use IRQF_NO_AUTOEN to ensure that the IRQ stays disabled until the first
> measurement, rather than enabling it briefly between request_irq() and
> disable_irq_nosync(). Cache the IRQ number and check errors from
> gpiod_to_irq().
>
> Fixes: 251eb40f5ccd ("hwmon: sht15 humidity sensor driver")
> Assisted-by: LLM
> Co-developed-by: Ijae Kim <ae878000@gmail.com>
> Signed-off-by: Ijae Kim <ae878000@gmail.com>
> Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
> ---
> Compile-tested (W=1). No runtime testing.
>
> Changes in v2:
> - Replace managed IRQ request/free with request_irq()/free_irq().
> - Use IRQF_NO_AUTOEN and cache the data GPIO IRQ.
That replaces a relatively simple patch with a much more complex
one, and Sashiko takes offense with it. What is the problem with
the original code ?
Guenter
> - Preserve asynchronous work drain ordering on probe failure and remove.
>
> drivers/hwmon/sht15.c | 47 +++++++++++++++++++++++++++++++++--------------
> 1 file changed, 33 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
> index 7bb2105d1ae223e7131ba4cc0523e4e074e01302..c95acec7ae2f8f57a10bd72f65a2905e64c3c58c 100644
> --- a/drivers/hwmon/sht15.c
> +++ b/drivers/hwmon/sht15.c
> @@ -31,6 +31,7 @@
> #include <linux/bitrev.h>
> #include <linux/gpio/consumer.h>
> #include <linux/of.h>
> +#include <linux/workqueue.h>
>
> /* Commands */
> #define SHT15_MEASURE_TEMP 0x03
> @@ -120,6 +121,7 @@ static const u8 sht15_crc8_table[] = {
> * struct sht15_data - device instance specific data
> * @sck: clock GPIO line
> * @data: data GPIO line
> + * @irq: interrupt number for the data GPIO line.
> * @read_work: bh of interrupt handler.
> * @wait_queue: wait queue for getting values from device.
> * @val_temp: last temperature value read from device.
> @@ -149,6 +151,7 @@ static const u8 sht15_crc8_table[] = {
> struct sht15_data {
> struct gpio_desc *sck;
> struct gpio_desc *data;
> + int irq;
> struct work_struct read_work;
> wait_queue_head_t wait_queue;
> uint16_t val_temp;
> @@ -532,9 +535,9 @@ static int sht15_measurement(struct sht15_data *data,
> return ret;
> atomic_set(&data->interrupt_handled, 0);
>
> - enable_irq(gpiod_to_irq(data->data));
> + enable_irq(data->irq);
> if (gpiod_get_value(data->data) == 0) {
> - disable_irq_nosync(gpiod_to_irq(data->data));
> + disable_irq_nosync(data->irq);
> /* Only relevant if the interrupt hasn't occurred. */
> if (!atomic_read(&data->interrupt_handled))
> schedule_work(&data->read_work);
> @@ -546,7 +549,7 @@ static int sht15_measurement(struct sht15_data *data,
> data->state = SHT15_READING_NOTHING;
> return -EIO;
> } else if (ret == 0) { /* timeout occurred */
> - disable_irq_nosync(gpiod_to_irq(data->data));
> + disable_irq_nosync(data->irq);
> ret = sht15_connection_reset(data);
> if (ret)
> return ret;
> @@ -825,7 +828,7 @@ static void sht15_bh_read_data(struct work_struct *work_s)
> * have gone low in meantime so verify it hasn't!
> */
> atomic_set(&data->interrupt_handled, 0);
> - enable_irq(gpiod_to_irq(data->data));
> + enable_irq(data->irq);
> /* If still not occurred or another handler was scheduled */
> if (gpiod_get_value(data->data)
> || atomic_read(&data->interrupt_handled))
> @@ -976,25 +979,31 @@ static int sht15_probe(struct platform_device *pdev)
> goto err_release_reg;
> }
>
> - ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
> - sht15_interrupt_fired,
> - IRQF_TRIGGER_FALLING,
> - "sht15 data",
> - data);
> - if (ret)
> + data->irq = gpiod_to_irq(data->data);
> + if (data->irq < 0) {
> + ret = data->irq;
> + goto err_release_reg;
> + }
> +
> + ret = request_irq(data->irq, sht15_interrupt_fired,
> + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
> + "sht15 data", data);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to get irq for data line\n");
> goto err_release_reg;
> - disable_irq_nosync(gpiod_to_irq(data->data));
> + }
> + /* IRQ remains disabled until a measurement starts. */
> ret = sht15_connection_reset(data);
> if (ret)
> - goto err_release_reg;
> + goto err_free_irq;
> ret = sht15_soft_reset(data);
> if (ret)
> - goto err_release_reg;
> + goto err_free_irq;
>
> ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
> if (ret) {
> dev_err(&pdev->dev, "sysfs create failed\n");
> - goto err_release_reg;
> + goto err_free_irq;
> }
>
> data->hwmon_dev = hwmon_device_register(data->dev);
> @@ -1007,9 +1016,14 @@ static int sht15_probe(struct platform_device *pdev)
>
> err_release_sysfs_group:
> sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
> +err_free_irq:
> + /* The read worker can re-enable the IRQ, so drain it first. */
> + disable_work_sync(&data->read_work);
> + free_irq(data->irq, data);
> err_release_reg:
> if (!IS_ERR(data->reg)) {
> regulator_unregister_notifier(data->reg, &data->nb);
> + cancel_work_sync(&data->update_supply_work);
> regulator_disable(data->reg);
> }
> return ret;
> @@ -1023,12 +1037,17 @@ static void sht15_remove(struct platform_device *pdev)
> hwmon_device_unregister(data->hwmon_dev);
> sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
>
> + /* The worker can re-enable the IRQ, so stop it before free_irq(). */
> + disable_work_sync(&data->read_work);
> + free_irq(data->irq, data);
> +
> ret = sht15_soft_reset(data);
> if (ret)
> dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
>
> if (!IS_ERR(data->reg)) {
> regulator_unregister_notifier(data->reg, &data->nb);
> + cancel_work_sync(&data->update_supply_work);
> regulator_disable(data->reg);
> }
> }
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources
2026-10-20 0:37 ` Guenter Roeck
@ 2026-10-20 23:37 ` Myeonghun Pak
0 siblings, 0 replies; 4+ messages in thread
From: Myeonghun Pak @ 2026-10-20 23:37 UTC (permalink / raw)
To: Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Ijae Kim
Hi Guenter,
The original issue is that read_work can remain pending after a
measurement timeout, while unregistering the regulator notifier does
not drain previously queued update_supply_work. Both may access
resources after they are released.
You're right that v2 is unnecessarily complex. I'll remove
IRQF_NO_AUTOEN and the IRQ caching changes, and keep only the explicit
IRQ teardown and work synchronization in v3.
Thanks for the review.
Best regards,
Myeonghun Pak
2026년 10월 19일 (월) 오후 8:37, Guenter Roeck <linux@roeck-us.net>님이 작성:
>
> On 10/19/26 16:44, Myeonghun Pak wrote:
> > The IRQ handler can queue read_work, which accesses GPIOs and may re-enable
> > that same IRQ. A measurement can return while read_work is still pending
> > or running. The regulator notifier can also queue update_supply_work,
> > which accesses the regulator. Neither work item was drained on removal
> > or on all probe failure paths before the managed resources were released.
> >
> > Use request_irq() and free_irq() since the IRQ must be released at an
> > explicit point in the teardown sequence. Disable and drain read_work
> > before freeing the IRQ. Unregister the regulator notifier before draining
> > update_supply_work and disabling the regulator.
> >
> > Use IRQF_NO_AUTOEN to ensure that the IRQ stays disabled until the first
> > measurement, rather than enabling it briefly between request_irq() and
> > disable_irq_nosync(). Cache the IRQ number and check errors from
> > gpiod_to_irq().
> >
> > Fixes: 251eb40f5ccd ("hwmon: sht15 humidity sensor driver")
> > Assisted-by: LLM
> > Co-developed-by: Ijae Kim <ae878000@gmail.com>
> > Signed-off-by: Ijae Kim <ae878000@gmail.com>
> > Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
> > ---
> > Compile-tested (W=1). No runtime testing.
> >
> > Changes in v2:
> > - Replace managed IRQ request/free with request_irq()/free_irq().
> > - Use IRQF_NO_AUTOEN and cache the data GPIO IRQ.
>
> That replaces a relatively simple patch with a much more complex
> one, and Sashiko takes offense with it. What is the problem with
> the original code ?
>
> Guenter
>
> > - Preserve asynchronous work drain ordering on probe failure and remove.
> >
> > drivers/hwmon/sht15.c | 47 +++++++++++++++++++++++++++++++++--------------
> > 1 file changed, 33 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
> > index 7bb2105d1ae223e7131ba4cc0523e4e074e01302..c95acec7ae2f8f57a10bd72f65a2905e64c3c58c 100644
> > --- a/drivers/hwmon/sht15.c
> > +++ b/drivers/hwmon/sht15.c
> > @@ -31,6 +31,7 @@
> > #include <linux/bitrev.h>
> > #include <linux/gpio/consumer.h>
> > #include <linux/of.h>
> > +#include <linux/workqueue.h>
> >
> > /* Commands */
> > #define SHT15_MEASURE_TEMP 0x03
> > @@ -120,6 +121,7 @@ static const u8 sht15_crc8_table[] = {
> > * struct sht15_data - device instance specific data
> > * @sck: clock GPIO line
> > * @data: data GPIO line
> > + * @irq: interrupt number for the data GPIO line.
> > * @read_work: bh of interrupt handler.
> > * @wait_queue: wait queue for getting values from device.
> > * @val_temp: last temperature value read from device.
> > @@ -149,6 +151,7 @@ static const u8 sht15_crc8_table[] = {
> > struct sht15_data {
> > struct gpio_desc *sck;
> > struct gpio_desc *data;
> > + int irq;
> > struct work_struct read_work;
> > wait_queue_head_t wait_queue;
> > uint16_t val_temp;
> > @@ -532,9 +535,9 @@ static int sht15_measurement(struct sht15_data *data,
> > return ret;
> > atomic_set(&data->interrupt_handled, 0);
> >
> > - enable_irq(gpiod_to_irq(data->data));
> > + enable_irq(data->irq);
> > if (gpiod_get_value(data->data) == 0) {
> > - disable_irq_nosync(gpiod_to_irq(data->data));
> > + disable_irq_nosync(data->irq);
> > /* Only relevant if the interrupt hasn't occurred. */
> > if (!atomic_read(&data->interrupt_handled))
> > schedule_work(&data->read_work);
> > @@ -546,7 +549,7 @@ static int sht15_measurement(struct sht15_data *data,
> > data->state = SHT15_READING_NOTHING;
> > return -EIO;
> > } else if (ret == 0) { /* timeout occurred */
> > - disable_irq_nosync(gpiod_to_irq(data->data));
> > + disable_irq_nosync(data->irq);
> > ret = sht15_connection_reset(data);
> > if (ret)
> > return ret;
> > @@ -825,7 +828,7 @@ static void sht15_bh_read_data(struct work_struct *work_s)
> > * have gone low in meantime so verify it hasn't!
> > */
> > atomic_set(&data->interrupt_handled, 0);
> > - enable_irq(gpiod_to_irq(data->data));
> > + enable_irq(data->irq);
> > /* If still not occurred or another handler was scheduled */
> > if (gpiod_get_value(data->data)
> > || atomic_read(&data->interrupt_handled))
> > @@ -976,25 +979,31 @@ static int sht15_probe(struct platform_device *pdev)
> > goto err_release_reg;
> > }
> >
> > - ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
> > - sht15_interrupt_fired,
> > - IRQF_TRIGGER_FALLING,
> > - "sht15 data",
> > - data);
> > - if (ret)
> > + data->irq = gpiod_to_irq(data->data);
> > + if (data->irq < 0) {
> > + ret = data->irq;
> > + goto err_release_reg;
> > + }
> > +
> > + ret = request_irq(data->irq, sht15_interrupt_fired,
> > + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
> > + "sht15 data", data);
> > + if (ret) {
> > + dev_err(&pdev->dev, "failed to get irq for data line\n");
> > goto err_release_reg;
> > - disable_irq_nosync(gpiod_to_irq(data->data));
> > + }
> > + /* IRQ remains disabled until a measurement starts. */
> > ret = sht15_connection_reset(data);
> > if (ret)
> > - goto err_release_reg;
> > + goto err_free_irq;
> > ret = sht15_soft_reset(data);
> > if (ret)
> > - goto err_release_reg;
> > + goto err_free_irq;
> >
> > ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
> > if (ret) {
> > dev_err(&pdev->dev, "sysfs create failed\n");
> > - goto err_release_reg;
> > + goto err_free_irq;
> > }
> >
> > data->hwmon_dev = hwmon_device_register(data->dev);
> > @@ -1007,9 +1016,14 @@ static int sht15_probe(struct platform_device *pdev)
> >
> > err_release_sysfs_group:
> > sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
> > +err_free_irq:
> > + /* The read worker can re-enable the IRQ, so drain it first. */
> > + disable_work_sync(&data->read_work);
> > + free_irq(data->irq, data);
> > err_release_reg:
> > if (!IS_ERR(data->reg)) {
> > regulator_unregister_notifier(data->reg, &data->nb);
> > + cancel_work_sync(&data->update_supply_work);
> > regulator_disable(data->reg);
> > }
> > return ret;
> > @@ -1023,12 +1037,17 @@ static void sht15_remove(struct platform_device *pdev)
> > hwmon_device_unregister(data->hwmon_dev);
> > sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
> >
> > + /* The worker can re-enable the IRQ, so stop it before free_irq(). */
> > + disable_work_sync(&data->read_work);
> > + free_irq(data->irq, data);
> > +
> > ret = sht15_soft_reset(data);
> > if (ret)
> > dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
> >
> > if (!IS_ERR(data->reg)) {
> > regulator_unregister_notifier(data->reg, &data->nb);
> > + cancel_work_sync(&data->update_supply_work);
> > regulator_disable(data->reg);
> > }
> > }
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-20 23:37 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 23:44 [PATCH v2] hwmon: (sht15) Stop deferred work before releasing its resources Myeonghun Pak
2026-10-19 23:53 ` sashiko-bot
2026-10-20 0:37 ` Guenter Roeck
2026-10-20 23:37 ` Myeonghun Pak
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.