diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-30 08:24:02 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-30 08:24:02 -1000 |
| commit | 2228d64da8a66b319a847c1fe0e66527b643e2c1 (patch) | |
| tree | 920a15b7605a12d86b1ae5cc1580133ac704202e | |
| parent | a4395d81eca6a94026276fe70cfb20f5a0191f1f (diff) | |
| parent | 8a6d73e316f95e398a1de1d1f58314b6d3e7f641 (diff) | |
| download | linux-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.c | 38 |
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); - |
