Unverified Commit 04f96c93 authored by Zhu Ning's avatar Zhu Ning Committed by Mark Brown
Browse files

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: default avatarZhu Ning <zhuning0077@gmail.com>
Link: https://lore.kernel.org/r/20230717033223.42506-5-zhuning0077@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0663286e
Loading
Loading
Loading
Loading
+89 −20
Original line number Diff line number Diff line
@@ -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);
		} else {
			if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
				dev_dbg(comp->dev, "Headset detected");
			goto exit;
		}
		if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
			dev_dbg(comp->dev, "Headphone detected\n");
			snd_soc_jack_report(es8326->jack,
						    SND_JACK_HEADSET, SND_JACK_HEADSET);
				snd_soc_component_write(comp,
							ES8326_ADC1_SRC, es8326->mic1_src);
					SND_JACK_HEADPHONE, SND_JACK_HEADSET);
		} else {
				dev_dbg(comp->dev, "Headphone detected");
			dev_dbg(comp->dev, "Headset detected\n");
			snd_soc_jack_report(es8326->jack,
						    SND_JACK_HEADPHONE, SND_JACK_HEADSET);
			}
					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;
}