aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-03-12 12:31:50 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-03-12 14:12:09 -0400
commitc986564b3115ebd24a907515ac0b7ca2bef794f9 (patch)
treecae0cd0b3d16a800920e3ea579f61b54bfb93619 /sound
parent80f48143ffde97c48c5e550e2fcd2c9f8e77e554 (diff)
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>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8994.c69
1 files changed, 34 insertions, 35 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index bc12d097ef0d..15fcb1bb7148 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -3166,9 +3166,16 @@ static void wm8958_default_micdet(u16 status, void *data)
3166 3166
3167 /* If we have jackdet that will detect removal */ 3167 /* If we have jackdet that will detect removal */
3168 if (wm8994->jackdet) { 3168 if (wm8994->jackdet) {
3169 mutex_lock(&wm8994->accdet_lock);
3170
3169 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, 3171 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
3170 WM8958_MICD_ENA, 0); 3172 WM8958_MICD_ENA, 0);
3171 3173
3174 wm1811_jackdet_set_mode(codec,
3175 WM1811_JACKDET_MODE_JACK);
3176
3177 mutex_unlock(&wm8994->accdet_lock);
3178
3172 if (wm8994->pdata->jd_ext_cap) { 3179 if (wm8994->pdata->jd_ext_cap) {
3173 mutex_lock(&codec->mutex); 3180 mutex_lock(&codec->mutex);
3174 snd_soc_dapm_disable_pin(&codec->dapm, 3181 snd_soc_dapm_disable_pin(&codec->dapm,
@@ -3176,9 +3183,6 @@ static void wm8958_default_micdet(u16 status, void *data)
3176 snd_soc_dapm_sync(&codec->dapm); 3183 snd_soc_dapm_sync(&codec->dapm);
3177 mutex_unlock(&codec->mutex); 3184 mutex_unlock(&codec->mutex);
3178 } 3185 }
3179
3180 wm1811_jackdet_set_mode(codec,
3181 WM1811_JACKDET_MODE_JACK);
3182 } 3186 }
3183 } 3187 }
3184 3188
@@ -3213,6 +3217,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
3213 struct wm8994_priv *wm8994 = data; 3217 struct wm8994_priv *wm8994 = data;
3214 struct snd_soc_codec *codec = wm8994->codec; 3218 struct snd_soc_codec *codec = wm8994->codec;
3215 int reg; 3219 int reg;
3220 bool present;
3216 3221
3217 mutex_lock(&wm8994->accdet_lock); 3222 mutex_lock(&wm8994->accdet_lock);
3218 3223
@@ -3225,11 +3230,10 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
3225 3230
3226 dev_dbg(codec->dev, "JACKDET %x\n", reg); 3231 dev_dbg(codec->dev, "JACKDET %x\n", reg);
3227 3232
3228 if (reg & WM1811_JACKDET_LVL) { 3233 present = reg & WM1811_JACKDET_LVL;
3229 dev_dbg(codec->dev, "Jack detected\n");
3230 3234
3231 snd_soc_jack_report(wm8994->micdet[0].jack, 3235 if (present) {
3232 SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); 3236 dev_dbg(codec->dev, "Jack detected\n");
3233 3237
3234 snd_soc_update_bits(codec, WM8958_MICBIAS2, 3238 snd_soc_update_bits(codec, WM8958_MICBIAS2,
3235 WM8958_MICB2_DISCH, 0); 3239 WM8958_MICB2_DISCH, 0);
@@ -3247,32 +3251,12 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
3247 3251
3248 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, 3252 snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
3249 WM8958_MICD_ENA, WM8958_MICD_ENA); 3253 WM8958_MICD_ENA, WM8958_MICD_ENA);
3250
3251 /* If required for an external cap force MICBIAS on */
3252 if (wm8994->pdata->jd_ext_cap) {
3253 mutex_lock(&codec->mutex);
3254 snd_soc_dapm_force_enable_pin(&codec->dapm,
3255 "MICBIAS2");
3256 snd_soc_dapm_sync(&codec->dapm);
3257 mutex_unlock(&codec->mutex);
3258 }
3259 } else { 3254 } else {
3260 dev_dbg(codec->dev, "Jack not detected\n"); 3255 dev_dbg(codec->dev, "Jack not detected\n");
3261 3256
3262 snd_soc_update_bits(codec, WM8958_MICBIAS2, 3257 snd_soc_update_bits(codec, WM8958_MICBIAS2,
3263 WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); 3258 WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
3264 3259
3265 if (wm8994->pdata->jd_ext_cap) {
3266 mutex_lock(&codec->mutex);
3267 snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
3268 snd_soc_dapm_sync(&codec->dapm);
3269 mutex_unlock(&codec->mutex);
3270 }
3271
3272 snd_soc_jack_report(wm8994->micdet[0].jack, 0,
3273 SND_JACK_MECHANICAL | SND_JACK_HEADSET |
3274 wm8994->btn_mask);
3275
3276 /* Enable debounce while removed */ 3260 /* Enable debounce while removed */
3277 snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, 3261 snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
3278 WM1811_JACKDET_DB, WM1811_JACKDET_DB); 3262 WM1811_JACKDET_DB, WM1811_JACKDET_DB);
@@ -3286,6 +3270,28 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
3286 3270
3287 mutex_unlock(&wm8994->accdet_lock); 3271 mutex_unlock(&wm8994->accdet_lock);
3288 3272
3273 /* If required for an external cap force MICBIAS on */
3274 if (wm8994->pdata->jd_ext_cap) {
3275 mutex_lock(&codec->mutex);
3276
3277 if (present)
3278 snd_soc_dapm_force_enable_pin(&codec->dapm,
3279 "MICBIAS2");
3280 else
3281 snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
3282
3283 snd_soc_dapm_sync(&codec->dapm);
3284 mutex_unlock(&codec->mutex);
3285 }
3286
3287 if (present)
3288 snd_soc_jack_report(wm8994->micdet[0].jack,
3289 SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
3290 else
3291 snd_soc_jack_report(wm8994->micdet[0].jack, 0,
3292 SND_JACK_MECHANICAL | SND_JACK_HEADSET |
3293 wm8994->btn_mask);
3294
3289 return IRQ_HANDLED; 3295 return IRQ_HANDLED;
3290} 3296}
3291 3297
@@ -3389,17 +3395,13 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
3389 struct snd_soc_codec *codec = wm8994->codec; 3395 struct snd_soc_codec *codec = wm8994->codec;
3390 int reg, count; 3396 int reg, count;
3391 3397
3392 mutex_lock(&wm8994->accdet_lock);
3393
3394 /* 3398 /*
3395 * Jack detection may have detected a removal simulataneously 3399 * Jack detection may have detected a removal simulataneously
3396 * with an update of the MICDET status; if so it will have 3400 * with an update of the MICDET status; if so it will have
3397 * stopped detection and we can ignore this interrupt. 3401 * stopped detection and we can ignore this interrupt.
3398 */ 3402 */
3399 if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) { 3403 if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
3400 mutex_unlock(&wm8994->accdet_lock);
3401 return IRQ_HANDLED; 3404 return IRQ_HANDLED;
3402 }
3403 3405
3404 /* We may occasionally read a detection without an impedence 3406 /* We may occasionally read a detection without an impedence
3405 * range being provided - if that happens loop again. 3407 * range being provided - if that happens loop again.
@@ -3408,7 +3410,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
3408 do { 3410 do {
3409 reg = snd_soc_read(codec, WM8958_MIC_DETECT_3); 3411 reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
3410 if (reg < 0) { 3412 if (reg < 0) {
3411 mutex_unlock(&wm8994->accdet_lock);
3412 dev_err(codec->dev, 3413 dev_err(codec->dev,
3413 "Failed to read mic detect status: %d\n", 3414 "Failed to read mic detect status: %d\n",
3414 reg); 3415 reg);
@@ -3439,8 +3440,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
3439 dev_warn(codec->dev, "Accessory detection with no callback\n"); 3440 dev_warn(codec->dev, "Accessory detection with no callback\n");
3440 3441
3441out: 3442out:
3442 mutex_unlock(&wm8994->accdet_lock);
3443
3444 return IRQ_HANDLED; 3443 return IRQ_HANDLED;
3445} 3444}
3446 3445