mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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:
parent
0663286e58
commit
04f96c9340
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user