Unverified Commit ee70bace authored by Cristian Ciocaltea's avatar Cristian Ciocaltea Committed by Mark Brown
Browse files

ASoC: nau8821: Avoid unnecessary blocking in IRQ handler



The interrupt handler offloads the microphone detection logic to
nau8821_jdet_work(), which implies a sleep operation.  However, before
being able to process any subsequent hotplug event, the interrupt
handler needs to wait for any prior scheduled work to complete.

Move the sleep out of jdet_work by converting it to a delayed work.
This eliminates the undesired blocking in the interrupt handler when
attempting to cancel a recently scheduled work item and should help
reducing transient input reports that might confuse user-space.

Signed-off-by: default avatarCristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2b4eda7b
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -1104,16 +1104,12 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
static void nau8821_jdet_work(struct work_struct *work)
{
	struct nau8821 *nau8821 =
		container_of(work, struct nau8821, jdet_work);
		container_of(work, struct nau8821, jdet_work.work);
	struct snd_soc_dapm_context *dapm = nau8821->dapm;
	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
	struct regmap *regmap = nau8821->regmap;
	int jack_status_reg, mic_detected, event = 0, event_mask = 0;

	snd_soc_component_force_enable_pin(component, "MICBIAS");
	snd_soc_dapm_sync(dapm);
	msleep(20);

	regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg);
	mic_detected = !(jack_status_reg & NAU8821_KEYDET);
	if (mic_detected) {
@@ -1146,6 +1142,7 @@ static void nau8821_jdet_work(struct work_struct *work)
		snd_soc_component_disable_pin(component, "MICBIAS");
		snd_soc_dapm_sync(dapm);
	}

	event_mask |= SND_JACK_HEADSET;
	snd_soc_jack_report(nau8821->jack, event, event_mask);
}
@@ -1194,6 +1191,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
{
	struct nau8821 *nau8821 = (struct nau8821 *)data;
	struct regmap *regmap = nau8821->regmap;
	struct snd_soc_component *component;
	int active_irq, event = 0, event_mask = 0;

	if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) {
@@ -1205,7 +1203,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)

	if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) ==
		NAU8821_JACK_EJECT_DETECTED) {
		cancel_work_sync(&nau8821->jdet_work);
		cancel_delayed_work_sync(&nau8821->jdet_work);
		regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
			NAU8821_MICDET_MASK, NAU8821_MICDET_DIS);
		nau8821_eject_jack(nau8821);
@@ -1219,12 +1217,15 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
		nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ);
	} else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
		NAU8821_JACK_INSERT_DETECTED) {
		cancel_work_sync(&nau8821->jdet_work);
		cancel_delayed_work_sync(&nau8821->jdet_work);
		regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
			NAU8821_MICDET_MASK, NAU8821_MICDET_EN);
		if (nau8821_is_jack_inserted(regmap)) {
			/* detect microphone and jack type */
			schedule_work(&nau8821->jdet_work);
			/* Detect microphone and jack type */
			component = snd_soc_dapm_to_component(nau8821->dapm);
			snd_soc_component_force_enable_pin(component, "MICBIAS");
			snd_soc_dapm_sync(nau8821->dapm);
			schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20));
			/* Turn off insertion interruption at manual mode */
			nau8821_setup_inserted_irq(nau8821);
		} else {
@@ -1661,7 +1662,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component,

	nau8821->jack = jack;
	/* Initiate jack detection work queue */
	INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work);
	INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work);

	ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL,
		nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
		"nau8821", nau8821);
+1 −1
Original line number Diff line number Diff line
@@ -561,7 +561,7 @@ struct nau8821 {
	struct regmap *regmap;
	struct snd_soc_dapm_context *dapm;
	struct snd_soc_jack *jack;
	struct work_struct jdet_work;
	struct delayed_work jdet_work;
	int irq;
	int clk_id;
	int micbias_voltage;