mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
extcon: arizona: Fix some issues when HPDET IRQ fires after the jack has been unplugged
[ Upstream commit c309a3e8793f7e01c4a4ec7960658380572cb576 ]
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 <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Acked-by: Charles Keepax <[email protected]>
Tested-by: Charles Keepax <[email protected]>
Acked-by: Chanwoo Choi <[email protected]>
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
This commit is contained in:
parent
22ee443ac7
commit
32990455bd
1 changed files with 9 additions and 8 deletions
|
|
@ -597,7 +597,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);
|
||||
|
|
@ -610,12 +610,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;
|
||||
}
|
||||
|
|
@ -668,7 +667,7 @@ done:
|
|||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
||||
|
||||
/* 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) {
|
||||
|
|
@ -676,7 +675,9 @@ done:
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue