ASoC: codecs: ES8326: Update jact detection function

The old jack detection function only supports fixed OMTP/CTIA
hardware connection. The new one supports auto OMTP/CTIA
headset detection

Signed-off-by: Zhu Ning <zhuning0077@gmail.com>
Link: https://lore.kernel.org/r/20230717033223.42506-5-zhuning0077@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Zhu Ning 2023-07-17 11:32:23 +08:00 committed by Mark Brown
parent 0663286e58
commit 04f96c9340
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -41,6 +41,8 @@ struct es8326_priv {
bool calibrated;
int version;
int hp;
int jack_remove_retry;
};
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@ -535,6 +537,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
cur_button = SND_JACK_BTN_0;
break;
case 0x6f:
case 0x4b:
/* button volume up */
cur_button = SND_JACK_BTN_1;
break;
@ -543,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
cur_button = SND_JACK_BTN_2;
break;
case 0x1e:
case 0xe2:
/* button released or not pressed */
cur_button = 0;
break;
@ -552,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work)
if ((prev_button == cur_button) && (cur_button != 0)) {
press_count++;
if (press_count > 10) {
/* report a press every 500ms */
if (press_count > 3) {
/* report a press every 120ms */
snd_soc_jack_report(es8326->jack, cur_button,
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
press_count = 0;
}
button_to_report = cur_button;
queue_delayed_work(system_wq, &es8326->button_press_work,
msecs_to_jiffies(50));
msecs_to_jiffies(35));
} else if (prev_button != cur_button) {
/* mismatch, detect again */
prev_button = cur_button;
queue_delayed_work(system_wq, &es8326->button_press_work,
msecs_to_jiffies(50));
msecs_to_jiffies(35));
} else {
/* released or no pressed */
if (button_to_report != 0) {
@ -589,32 +593,96 @@ static void es8326_jack_detect_handler(struct work_struct *work)
mutex_lock(&es8326->lock);
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
if (es8326->jack_remove_retry == 1) {
if (iface & ES8326_HPINSERT_FLAG)
es8326->jack_remove_retry = 2;
else
es8326->jack_remove_retry = 0;
dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n",
es8326->jack_remove_retry);
/*
* Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
*/
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
~es8326->jack_pol : es8326->jack_pol));
goto exit;
}
if ((iface & ES8326_HPINSERT_FLAG) == 0) {
/* Jack unplugged or spurious IRQ */
dev_dbg(comp->dev, "No headset detected");
dev_dbg(comp->dev, "No headset detected\n");
es8326_disable_micbias(es8326->component);
if (es8326->jack->status & SND_JACK_HEADPHONE) {
dev_dbg(comp->dev, "Report hp remove event\n");
snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
es8326_disable_micbias(comp);
/* mute adc when mic path switch */
regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
es8326->hp = 0;
}
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
/*
* Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
*/
if (es8326->jack_remove_retry == 0) {
es8326->jack_remove_retry = 1;
dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n",
es8326->jack_remove_retry);
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
es8326->jack_pol : ~es8326->jack_pol));
} else {
es8326->jack_remove_retry = 0;
}
} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
es8326->jack_remove_retry = 0;
if (es8326->hp == 0) {
dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n");
/*
* set auto-check mode, then restart jack_detect_work after 100ms.
* Don't report jack status.
*/
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
usleep_range(50000, 70000);
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
queue_delayed_work(system_wq, &es8326->jack_detect_work,
msecs_to_jiffies(100));
es8326->hp = 1;
goto exit;
}
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
dev_dbg(comp->dev, "button pressed\n");
queue_delayed_work(system_wq, &es8326->button_press_work, 10);
goto exit;
}
if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
dev_dbg(comp->dev, "Headphone detected\n");
snd_soc_jack_report(es8326->jack,
SND_JACK_HEADPHONE, SND_JACK_HEADSET);
} else {
if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
dev_dbg(comp->dev, "Headset detected");
snd_soc_jack_report(es8326->jack,
SND_JACK_HEADSET, SND_JACK_HEADSET);
snd_soc_component_write(comp,
ES8326_ADC1_SRC, es8326->mic1_src);
} else {
dev_dbg(comp->dev, "Headphone detected");
snd_soc_jack_report(es8326->jack,
SND_JACK_HEADPHONE, SND_JACK_HEADSET);
}
dev_dbg(comp->dev, "Headset detected\n");
snd_soc_jack_report(es8326->jack,
SND_JACK_HEADSET, SND_JACK_HEADSET);
regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
0x08, 0x08);
regmap_update_bits(es8326->regmap, ES8326_PGAGAIN,
0x80, 0x80);
regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
0x08, 0x00);
usleep_range(10000, 15000);
}
}
exit:
mutex_unlock(&es8326->lock);
}
@ -633,7 +701,7 @@ static irqreturn_t es8326_irq(int irq, void *dev_id)
msecs_to_jiffies(10));
else
queue_delayed_work(system_wq, &es8326->jack_detect_work,
msecs_to_jiffies(300));
msecs_to_jiffies(600));
out:
return IRQ_HANDLED;
@ -763,7 +831,8 @@ static int es8326_resume(struct snd_soc_component *component)
(ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
(ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
es8326_irq(es8326->irq, es8326);
es8326->jack_remove_retry = 0;
es8326->hp = 0;
return 0;
}