|
@@ -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);
|