Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Cristian Ciocaltea and committed by
Mark Brown
ee70bace 2b4eda7b

+13 -11
+12 -10
sound/soc/codecs/nau8821.c
··· 1104 1104 static void nau8821_jdet_work(struct work_struct *work) 1105 1105 { 1106 1106 struct nau8821 *nau8821 = 1107 - container_of(work, struct nau8821, jdet_work); 1107 + container_of(work, struct nau8821, jdet_work.work); 1108 1108 struct snd_soc_dapm_context *dapm = nau8821->dapm; 1109 1109 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); 1110 1110 struct regmap *regmap = nau8821->regmap; 1111 1111 int jack_status_reg, mic_detected, event = 0, event_mask = 0; 1112 - 1113 - snd_soc_component_force_enable_pin(component, "MICBIAS"); 1114 - snd_soc_dapm_sync(dapm); 1115 - msleep(20); 1116 1112 1117 1113 regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg); 1118 1114 mic_detected = !(jack_status_reg & NAU8821_KEYDET); ··· 1142 1146 snd_soc_component_disable_pin(component, "MICBIAS"); 1143 1147 snd_soc_dapm_sync(dapm); 1144 1148 } 1149 + 1145 1150 event_mask |= SND_JACK_HEADSET; 1146 1151 snd_soc_jack_report(nau8821->jack, event, event_mask); 1147 1152 } ··· 1191 1194 { 1192 1195 struct nau8821 *nau8821 = (struct nau8821 *)data; 1193 1196 struct regmap *regmap = nau8821->regmap; 1197 + struct snd_soc_component *component; 1194 1198 int active_irq, event = 0, event_mask = 0; 1195 1199 1196 1200 if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { ··· 1203 1205 1204 1206 if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) == 1205 1207 NAU8821_JACK_EJECT_DETECTED) { 1206 - cancel_work_sync(&nau8821->jdet_work); 1208 + cancel_delayed_work_sync(&nau8821->jdet_work); 1207 1209 regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, 1208 1210 NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); 1209 1211 nau8821_eject_jack(nau8821); ··· 1217 1219 nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); 1218 1220 } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == 1219 1221 NAU8821_JACK_INSERT_DETECTED) { 1220 - cancel_work_sync(&nau8821->jdet_work); 1222 + cancel_delayed_work_sync(&nau8821->jdet_work); 1221 1223 regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, 1222 1224 NAU8821_MICDET_MASK, NAU8821_MICDET_EN); 1223 1225 if (nau8821_is_jack_inserted(regmap)) { 1224 - /* detect microphone and jack type */ 1225 - schedule_work(&nau8821->jdet_work); 1226 + /* Detect microphone and jack type */ 1227 + component = snd_soc_dapm_to_component(nau8821->dapm); 1228 + snd_soc_component_force_enable_pin(component, "MICBIAS"); 1229 + snd_soc_dapm_sync(nau8821->dapm); 1230 + schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20)); 1226 1231 /* Turn off insertion interruption at manual mode */ 1227 1232 nau8821_setup_inserted_irq(nau8821); 1228 1233 } else { ··· 1662 1661 1663 1662 nau8821->jack = jack; 1664 1663 /* Initiate jack detection work queue */ 1665 - INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work); 1664 + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); 1665 + 1666 1666 ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, 1667 1667 nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, 1668 1668 "nau8821", nau8821);
+1 -1
sound/soc/codecs/nau8821.h
··· 561 561 struct regmap *regmap; 562 562 struct snd_soc_dapm_context *dapm; 563 563 struct snd_soc_jack *jack; 564 - struct work_struct jdet_work; 564 + struct delayed_work jdet_work; 565 565 int irq; 566 566 int clk_id; 567 567 int micbias_voltage;