diff options
author | Mark Brown <broonie@kernel.org> | 2017-04-11 16:58:30 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-04-11 16:58:30 +0100 |
commit | b8d4f7a30bab878d8909bb6ee73e8ac47a1646bf (patch) | |
tree | bb823543361a4ce60327b922f2f202627e6dac40 /sound/soc | |
parent | 17febfa6071bc673892edda6b1998ccfc7456c4e (diff) | |
parent | d7344010d183ad62d1ababca3beb9553cf5e1546 (diff) |
Merge branch 'topic/jack' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-rt5665
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/soc-jack.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index fbaa1bb41102..7daf21fee355 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -19,9 +19,28 @@ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/export.h> +#include <linux/suspend.h> #include <trace/events/asoc.h> /** + * snd_soc_codec_set_jack - configure codec jack. + * @codec: CODEC + * @jack: structure to use for the jack + * @data: can be used if codec driver need extra data for configuring jack + * + * Configures and enables jack detection function. + */ +int snd_soc_codec_set_jack(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, void *data) +{ + if (codec->driver->set_jack) + return codec->driver->set_jack(codec, jack, data); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_set_jack); + +/** * snd_soc_card_jack_new - Create a new jack * @card: ASoC card * @id: an identifying string for this jack @@ -293,6 +312,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 +409,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 +475,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); |