mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 09:00:54 +07:00
ASoC: wm8994: Prevent ABBA deadlock with CODEC and accdet mutexes
Currently we can the accdet mutex from within DAPM when updating the device state which means we take accdet then the CODEC mutex but we also do the locking the other way around when responding to the jackdet IRQ. Move all the jackdet use of the CODEC mutex out of the accdet lock to avoid this. Since all the DAPM interactions depend only on a single threaded IRQ this is still serialised. The locking improvements in 3.5 allow a better solution there. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
80f48143ff
commit
c986564b31
@ -3166,9 +3166,16 @@ static void wm8958_default_micdet(u16 status, void *data)
|
||||
|
||||
/* If we have jackdet that will detect removal */
|
||||
if (wm8994->jackdet) {
|
||||
mutex_lock(&wm8994->accdet_lock);
|
||||
|
||||
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
|
||||
WM8958_MICD_ENA, 0);
|
||||
|
||||
wm1811_jackdet_set_mode(codec,
|
||||
WM1811_JACKDET_MODE_JACK);
|
||||
|
||||
mutex_unlock(&wm8994->accdet_lock);
|
||||
|
||||
if (wm8994->pdata->jd_ext_cap) {
|
||||
mutex_lock(&codec->mutex);
|
||||
snd_soc_dapm_disable_pin(&codec->dapm,
|
||||
@ -3176,9 +3183,6 @@ static void wm8958_default_micdet(u16 status, void *data)
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
mutex_unlock(&codec->mutex);
|
||||
}
|
||||
|
||||
wm1811_jackdet_set_mode(codec,
|
||||
WM1811_JACKDET_MODE_JACK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3213,6 +3217,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
|
||||
struct wm8994_priv *wm8994 = data;
|
||||
struct snd_soc_codec *codec = wm8994->codec;
|
||||
int reg;
|
||||
bool present;
|
||||
|
||||
mutex_lock(&wm8994->accdet_lock);
|
||||
|
||||
@ -3225,11 +3230,10 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
|
||||
|
||||
dev_dbg(codec->dev, "JACKDET %x\n", reg);
|
||||
|
||||
if (reg & WM1811_JACKDET_LVL) {
|
||||
dev_dbg(codec->dev, "Jack detected\n");
|
||||
present = reg & WM1811_JACKDET_LVL;
|
||||
|
||||
snd_soc_jack_report(wm8994->micdet[0].jack,
|
||||
SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
|
||||
if (present) {
|
||||
dev_dbg(codec->dev, "Jack detected\n");
|
||||
|
||||
snd_soc_update_bits(codec, WM8958_MICBIAS2,
|
||||
WM8958_MICB2_DISCH, 0);
|
||||
@ -3247,32 +3251,12 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
|
||||
|
||||
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
|
||||
WM8958_MICD_ENA, WM8958_MICD_ENA);
|
||||
|
||||
/* If required for an external cap force MICBIAS on */
|
||||
if (wm8994->pdata->jd_ext_cap) {
|
||||
mutex_lock(&codec->mutex);
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"MICBIAS2");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
mutex_unlock(&codec->mutex);
|
||||
}
|
||||
} else {
|
||||
dev_dbg(codec->dev, "Jack not detected\n");
|
||||
|
||||
snd_soc_update_bits(codec, WM8958_MICBIAS2,
|
||||
WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
|
||||
|
||||
if (wm8994->pdata->jd_ext_cap) {
|
||||
mutex_lock(&codec->mutex);
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
mutex_unlock(&codec->mutex);
|
||||
}
|
||||
|
||||
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
|
||||
SND_JACK_MECHANICAL | SND_JACK_HEADSET |
|
||||
wm8994->btn_mask);
|
||||
|
||||
/* Enable debounce while removed */
|
||||
snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
|
||||
WM1811_JACKDET_DB, WM1811_JACKDET_DB);
|
||||
@ -3286,6 +3270,28 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
|
||||
|
||||
mutex_unlock(&wm8994->accdet_lock);
|
||||
|
||||
/* If required for an external cap force MICBIAS on */
|
||||
if (wm8994->pdata->jd_ext_cap) {
|
||||
mutex_lock(&codec->mutex);
|
||||
|
||||
if (present)
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm,
|
||||
"MICBIAS2");
|
||||
else
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
|
||||
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
mutex_unlock(&codec->mutex);
|
||||
}
|
||||
|
||||
if (present)
|
||||
snd_soc_jack_report(wm8994->micdet[0].jack,
|
||||
SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
|
||||
else
|
||||
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
|
||||
SND_JACK_MECHANICAL | SND_JACK_HEADSET |
|
||||
wm8994->btn_mask);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -3389,17 +3395,13 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
||||
struct snd_soc_codec *codec = wm8994->codec;
|
||||
int reg, count;
|
||||
|
||||
mutex_lock(&wm8994->accdet_lock);
|
||||
|
||||
/*
|
||||
* Jack detection may have detected a removal simulataneously
|
||||
* with an update of the MICDET status; if so it will have
|
||||
* stopped detection and we can ignore this interrupt.
|
||||
*/
|
||||
if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) {
|
||||
mutex_unlock(&wm8994->accdet_lock);
|
||||
if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* We may occasionally read a detection without an impedence
|
||||
* range being provided - if that happens loop again.
|
||||
@ -3408,7 +3410,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
||||
do {
|
||||
reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
|
||||
if (reg < 0) {
|
||||
mutex_unlock(&wm8994->accdet_lock);
|
||||
dev_err(codec->dev,
|
||||
"Failed to read mic detect status: %d\n",
|
||||
reg);
|
||||
@ -3439,8 +3440,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
||||
dev_warn(codec->dev, "Accessory detection with no callback\n");
|
||||
|
||||
out:
|
||||
mutex_unlock(&wm8994->accdet_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user