87 lines
3.0 KiB
Diff
87 lines
3.0 KiB
Diff
From c85886b2901593aef688b0c7a6a3b66222e99a90 Mon Sep 17 00:00:00 2001
|
|
From: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Tue, 22 Dec 2020 17:34:06 +0100
|
|
Subject: [PATCH 05/14] extcon: arizona: Fix some issues when HPDET IRQ fires
|
|
after the jack has been unplugged
|
|
|
|
When the jack is partially inserted and then removed again it may be
|
|
removed while the hpdet code is running. In this case the following
|
|
may happen:
|
|
|
|
1. The "JACKDET rise" or ""JACKDET fall" IRQ triggers
|
|
2. arizona_jackdet runs and takes info->lock
|
|
3. The "HPDET" IRQ triggers
|
|
4. arizona_hpdet_irq runs, blocks on info->lock
|
|
5. arizona_jackdet calls arizona_stop_mic() and clears info->hpdet_done
|
|
6. arizona_jackdet releases info->lock
|
|
7. arizona_hpdet_irq now can continue running and:
|
|
7.1 Calls arizona_start_mic() (if a mic was detected)
|
|
7.2 sets info->hpdet_done
|
|
|
|
Step 7 is undeseriable / a bug:
|
|
7.1 causes the device to stay in a high power-state (with MICVDD enabled)
|
|
7.2 causes hpdet to not run on the next jack insertion, which in turn
|
|
causes the EXTCON_JACK_HEADPHONE state to never get set
|
|
|
|
This fixes both issues by skipping these 2 steps when arizona_hpdet_irq
|
|
runs after the jack has been unplugged.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
---
|
|
drivers/extcon/extcon-arizona.c | 17 +++++++++--------
|
|
1 file changed, 9 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
|
|
index aae82db542a5..f7ef247de46a 100644
|
|
--- a/drivers/extcon/extcon-arizona.c
|
|
+++ b/drivers/extcon/extcon-arizona.c
|
|
@@ -601,7 +601,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
|
struct arizona *arizona = info->arizona;
|
|
int id_gpio = arizona->pdata.hpdet_id_gpio;
|
|
unsigned int report = EXTCON_JACK_HEADPHONE;
|
|
- int ret, reading;
|
|
+ int ret, reading, state;
|
|
bool mic = false;
|
|
|
|
mutex_lock(&info->lock);
|
|
@@ -614,12 +614,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
|
}
|
|
|
|
/* If the cable was removed while measuring ignore the result */
|
|
- ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
|
- if (ret < 0) {
|
|
- dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
|
- ret);
|
|
+ state = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
|
+ if (state < 0) {
|
|
+ dev_err(arizona->dev, "Failed to check cable state: %d\n", state);
|
|
goto out;
|
|
- } else if (!ret) {
|
|
+ } else if (!state) {
|
|
dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
|
|
goto done;
|
|
}
|
|
@@ -667,7 +666,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
|
gpio_set_value_cansleep(id_gpio, 0);
|
|
|
|
/* If we have a mic then reenable MICDET */
|
|
- if (mic || info->mic)
|
|
+ if (state && (mic || info->mic))
|
|
arizona_start_mic(info);
|
|
|
|
if (info->hpdet_active) {
|
|
@@ -675,7 +674,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
|
info->hpdet_active = false;
|
|
}
|
|
|
|
- info->hpdet_done = true;
|
|
+ /* Do not set hp_det done when the cable has been unplugged */
|
|
+ if (state)
|
|
+ info->hpdet_done = true;
|
|
|
|
out:
|
|
mutex_unlock(&info->lock);
|
|
--
|
|
2.28.0
|
|
|