ASoC: codecs: ES8326: Update jact detection function
authorZhu Ning <zhuning0077@gmail.com>
Mon, 17 Jul 2023 03:32:23 +0000 (11:32 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 25 Jul 2023 11:11:54 +0000 (12:11 +0100)
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>
sound/soc/codecs/es8326.c

index 8ffabc8..6c26308 100644 (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;
 }