summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-30 08:24:02 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-30 08:24:02 -1000
commit2228d64da8a66b319a847c1fe0e66527b643e2c1 (patch)
tree920a15b7605a12d86b1ae5cc1580133ac704202e
parenta4395d81eca6a94026276fe70cfb20f5a0191f1f (diff)
parent8a6d73e316f95e398a1de1d1f58314b6d3e7f641 (diff)
downloadlinux-2228d64da8a66b319a847c1fe0e66527b643e2c1.tar.gz
linux-2228d64da8a66b319a847c1fe0e66527b643e2c1.zip
Merge tag 'regulator-fix-v7.4-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator fix from Mark Brown: "One fix here, we had an issue with deferred hardware disables where if we were deferring while suspend was happening we would let the workqueue run which could result in us trying to access hardware after it or the buses used to access it were suspended. We fix this by completing any work as we suspend the individual regulators" * tag 'regulator-fix-v7.4-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: regulator: irq: freeze deferred hardware access during suspend
-rw-r--r--drivers/regulator/irq_helpers.c38
1 files changed, 22 insertions, 16 deletions
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
index 5b3cfac28667..cdbd170d2b15 100644
--- a/drivers/regulator/irq_helpers.c
+++ b/drivers/regulator/irq_helpers.c
@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <linux/regulator/driver.h>
#include "internal.h"
@@ -27,6 +28,7 @@ struct regulator_irq {
int irq;
int retry_cnt;
struct delayed_work isr_work;
+ struct workqueue_struct *wq;
};
/*
@@ -145,12 +147,7 @@ enable_out:
return;
reschedule:
- if (!d->high_prio)
- mod_delayed_work(system_dfl_wq, &h->isr_work,
- msecs_to_jiffies(tmo));
- else
- mod_delayed_work(system_highpri_wq, &h->isr_work,
- msecs_to_jiffies(tmo));
+ mod_delayed_work(h->wq, &h->isr_work, msecs_to_jiffies(tmo));
}
static irqreturn_t regulator_notifier_isr(int irq, void *data)
@@ -248,13 +245,8 @@ static irqreturn_t regulator_notifier_isr(int irq, void *data)
}
if (d->irq_off_ms) {
- if (!d->high_prio)
- schedule_delayed_work(&h->isr_work,
- msecs_to_jiffies(d->irq_off_ms));
- else
- mod_delayed_work(system_highpri_wq,
- &h->isr_work,
- msecs_to_jiffies(d->irq_off_ms));
+ mod_delayed_work(h->wq, &h->isr_work,
+ msecs_to_jiffies(d->irq_off_ms));
}
return IRQ_HANDLED;
@@ -363,13 +355,25 @@ void *regulator_irq_helper(struct device *dev,
init_rdev_errors(h);
- if (h->desc.irq_off_ms)
+ if (h->desc.irq_off_ms) {
+ if (h->desc.high_prio) {
+ h->wq = alloc_workqueue("regulator_irq_highpri",
+ WQ_FREEZABLE | WQ_HIGHPRI, 0);
+ if (!h->wq)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ h->wq = system_freezable_wq;
+ }
+
INIT_DELAYED_WORK(&h->isr_work, regulator_notifier_isr_work);
+ }
ret = request_threaded_irq(h->irq, NULL, regulator_notifier_isr,
IRQF_ONESHOT | irq_flags, h->desc.name, h);
if (ret) {
dev_err(dev, "Failed to request IRQ %d\n", irq);
+ if (h->desc.irq_off_ms && h->desc.high_prio)
+ destroy_workqueue(h->wq);
return ERR_PTR(ret);
}
@@ -393,8 +397,11 @@ void regulator_irq_helper_cancel(void **handle)
struct regulator_irq *h = *handle;
free_irq(h->irq, h);
- if (h->desc.irq_off_ms)
+ if (h->desc.irq_off_ms) {
cancel_delayed_work_sync(&h->isr_work);
+ if (h->desc.high_prio)
+ destroy_workqueue(h->wq);
+ }
h = NULL;
}
@@ -441,4 +448,3 @@ int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid,
return 0;
}
EXPORT_SYMBOL_GPL(regulator_irq_map_event_simple);
-