summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-jack.c30
2 files changed, 31 insertions, 0 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2b502f6cc6d0..1d20abec4995 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -722,6 +722,7 @@ struct snd_soc_jack_gpio {
/* private: */
struct snd_soc_jack *jack;
struct delayed_work work;
+ struct notifier_block pm_notifier;
struct gpio_desc *desc;
void *data;
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index fbaa1bb41102..a03dcbb94baf 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -19,6 +19,7 @@
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/suspend.h>
#include <trace/events/asoc.h>
/**
@@ -293,6 +294,27 @@ static void gpio_work(struct work_struct *work)
snd_soc_jack_gpio_detect(gpio);
}
+static int snd_soc_jack_pm_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct snd_soc_jack_gpio *gpio =
+ container_of(nb, struct snd_soc_jack_gpio, pm_notifier);
+
+ switch (action) {
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
+ /*
+ * Use workqueue so we do not have to care about running
+ * concurrently with work triggered by the interrupt handler.
+ */
+ queue_delayed_work(system_power_efficient_wq, &gpio->work, 0);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
/**
* snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
*
@@ -369,6 +391,13 @@ got_gpio:
i, ret);
}
+ /*
+ * Register PM notifier so we do not miss state transitions
+ * happening while system is asleep.
+ */
+ gpios[i].pm_notifier.notifier_call = snd_soc_jack_pm_notifier;
+ register_pm_notifier(&gpios[i].pm_notifier);
+
/* Expose GPIO value over sysfs for diagnostic purposes */
gpiod_export(gpios[i].desc, false);
@@ -428,6 +457,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
for (i = 0; i < count; i++) {
gpiod_unexport(gpios[i].desc);
+ unregister_pm_notifier(&gpios[i].pm_notifier);
free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
cancel_delayed_work_sync(&gpios[i].work);
gpiod_put(gpios[i].desc);