diff options
author | Peter Ujfalusi <peter.ujfalusi@linux.intel.com> | 2022-01-26 11:03:25 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2022-01-28 16:59:20 +0100 |
commit | 4045daf0fa87846a27f56329fddad2deeb5ca354 (patch) | |
tree | 10f277e77870ea7628e9a4b75d74f87f1eded872 /sound/soc/codecs/rt5682-i2c.c | |
parent | ASoC: hdmi-codec: Fix OOB memory accesses (diff) | |
download | linux-4045daf0fa87846a27f56329fddad2deeb5ca354.tar.xz linux-4045daf0fa87846a27f56329fddad2deeb5ca354.zip |
ASoC: rt5682: Fix deadlock on resume
On resume from suspend the following chain of events can happen:
A rt5682_resume() -> mod_delayed_work() for jack_detect_work
B DAPM sequence starts ( DAPM is locked now)
A1. rt5682_jack_detect_handler() scheduled
- Takes both jdet_mutex and calibrate_mutex
- Calls in to rt5682_headset_detect() which tries to take DAPM lock, it
starts to wait for it as B path took it already.
B1. DAPM sequence reaches the "HP Amp", rt5682_hp_event() tries to take
the jdet_mutex, but it is locked in A1, so it waits.
Deadlock.
To solve the deadlock, drop the jdet_mutex, use the jack_detect_work to do
the jack removal handling, move the dapm lock up one level to protect the
most of the rt5682_jack_detect_handler(), but not the jack reporting as it
might trigger a DAPM sequence.
The rt5682_headset_detect() can be changed to static as well.
Fixes: 8deb34a90f063 ("ASoC: rt5682: fix the wrong jack type detected")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20220126100325.16513-1-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/rt5682-i2c.c')
-rw-r--r-- | sound/soc/codecs/rt5682-i2c.c | 15 |
1 files changed, 4 insertions, 11 deletions
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 20e0f90ea498..20fc0f3766de 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work) struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv, jd_check_work.work); - if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) - & RT5682_JDH_RS_MASK) { + if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK) /* jack out */ - rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0); - - snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3); - } else { + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, 0); + else schedule_delayed_work(&rt5682->jd_check_work, 500); - } } static irqreturn_t rt5682_irq(int irq, void *data) @@ -198,7 +192,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, } mutex_init(&rt5682->calibrate_mutex); - mutex_init(&rt5682->jdet_mutex); rt5682_calibrate(rt5682); rt5682_apply_patch_list(rt5682, &i2c->dev); |