Skip to content

Commit

Permalink
extcon: arizona: Fix some issues when HPDET IRQ fires after the jack …
Browse files Browse the repository at this point in the history
…has been unplugged

[ Upstream commit c309a3e ]

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 undesirable / 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>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Acked-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Tested-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
jwrdegoede authored and gregkh committed May 12, 2021
1 parent 348c35a commit 381d0d2
Showing 1 changed file with 9 additions and 8 deletions.
17 changes: 9 additions & 8 deletions drivers/extcon/extcon-arizona.c
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -667,15 +666,17 @@ 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) {
pm_runtime_put_autosuspend(info->dev);
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);
Expand Down

0 comments on commit 381d0d2

Please sign in to comment.