Skip to content

Commit a698679

Browse files
cristiccbroonie
authored andcommitted
ASoC: nau8821: Consistently clear interrupts before unmasking
The interrupt handler attempts to perform some IRQ status clear operations *after* rather than *before* unmasking and enabling interrupts. This is a rather fragile approach since it may generally lead to missing IRQ requests or causing spurious interrupts. Make use of the nau8821_irq_status_clear() helper instead of manipulating the related register directly and ensure any interrupt clearing is performed *after* the target interrupts are disabled/masked and *before* proceeding with additional interrupt unmasking/enablement operations. This also implicitly drops the redundant clear operation of the ejection IRQ in the interrupt handler, since nau8821_eject_jack() has been already responsible for clearing all active interrupts. Fixes: aab1ad1 ("ASoC: nau8821: new driver") Fixes: 2551b6e ("ASoC: nau8821: Add headset button detection") Signed-off-by: Cristian Ciocaltea <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 9273aa8 commit a698679

File tree

1 file changed

+30
-28
lines changed

1 file changed

+30
-28
lines changed

sound/soc/codecs/nau8821.c

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,20 +1057,24 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
10571057
snd_soc_component_disable_pin(component, "MICBIAS");
10581058
snd_soc_dapm_sync(dapm);
10591059

1060+
/* Disable & mask both insertion & ejection IRQs */
1061+
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
1062+
NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS,
1063+
NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS);
1064+
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
1065+
NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN,
1066+
NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN);
1067+
10601068
/* Clear all interruption status */
10611069
nau8821_irq_status_clear(regmap, 0);
10621070

1063-
/* Enable the insertion interruption, disable the ejection inter-
1064-
* ruption, and then bypass de-bounce circuit.
1065-
*/
1071+
/* Enable & unmask the insertion IRQ */
10661072
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
1067-
NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS,
1068-
NAU8821_IRQ_EJECT_DIS);
1069-
/* Mask unneeded IRQs: 1 - disable, 0 - enable */
1073+
NAU8821_IRQ_INSERT_DIS, 0);
10701074
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
1071-
NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN,
1072-
NAU8821_IRQ_EJECT_EN);
1075+
NAU8821_IRQ_INSERT_EN, 0);
10731076

1077+
/* Bypass de-bounce circuit */
10741078
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
10751079
NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS);
10761080

@@ -1094,7 +1098,6 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
10941098
NAU8821_IRQ_KEY_RELEASE_DIS |
10951099
NAU8821_IRQ_KEY_PRESS_DIS);
10961100
}
1097-
10981101
}
10991102

11001103
static void nau8821_jdet_work(struct work_struct *work)
@@ -1151,6 +1154,15 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
11511154
{
11521155
struct regmap *regmap = nau8821->regmap;
11531156

1157+
/* Disable & mask insertion IRQ */
1158+
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
1159+
NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS);
1160+
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
1161+
NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN);
1162+
1163+
/* Clear insert IRQ status */
1164+
nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED);
1165+
11541166
/* Enable internal VCO needed for interruptions */
11551167
if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE)
11561168
nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0);
@@ -1169,17 +1181,18 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
11691181
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
11701182
NAU8821_JACK_DET_DB_BYPASS, 0);
11711183

1184+
/* Unmask & enable the ejection IRQs */
11721185
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
1173-
NAU8821_IRQ_EJECT_EN, 0);
1186+
NAU8821_IRQ_EJECT_EN, 0);
11741187
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
1175-
NAU8821_IRQ_EJECT_DIS, 0);
1188+
NAU8821_IRQ_EJECT_DIS, 0);
11761189
}
11771190

11781191
static irqreturn_t nau8821_interrupt(int irq, void *data)
11791192
{
11801193
struct nau8821 *nau8821 = (struct nau8821 *)data;
11811194
struct regmap *regmap = nau8821->regmap;
1182-
int active_irq, clear_irq = 0, event = 0, event_mask = 0;
1195+
int active_irq, event = 0, event_mask = 0;
11831196

11841197
if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) {
11851198
dev_err(nau8821->dev, "failed to read irq status\n");
@@ -1195,14 +1208,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
11951208
NAU8821_MICDET_MASK, NAU8821_MICDET_DIS);
11961209
nau8821_eject_jack(nau8821);
11971210
event_mask |= SND_JACK_HEADSET;
1198-
clear_irq = NAU8821_JACK_EJECT_IRQ_MASK;
11991211
} else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) {
12001212
event |= NAU8821_BUTTON;
12011213
event_mask |= NAU8821_BUTTON;
1202-
clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ;
1214+
nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ);
12031215
} else if (active_irq & NAU8821_KEY_RELEASE_IRQ) {
12041216
event_mask = NAU8821_BUTTON;
1205-
clear_irq = NAU8821_KEY_RELEASE_IRQ;
1217+
nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ);
12061218
} else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
12071219
NAU8821_JACK_INSERT_DETECTED) {
12081220
cancel_work_sync(&nau8821->jdet_work);
@@ -1212,27 +1224,17 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
12121224
/* detect microphone and jack type */
12131225
schedule_work(&nau8821->jdet_work);
12141226
/* Turn off insertion interruption at manual mode */
1215-
regmap_update_bits(regmap,
1216-
NAU8821_R12_INTERRUPT_DIS_CTRL,
1217-
NAU8821_IRQ_INSERT_DIS,
1218-
NAU8821_IRQ_INSERT_DIS);
1219-
regmap_update_bits(regmap,
1220-
NAU8821_R0F_INTERRUPT_MASK,
1221-
NAU8821_IRQ_INSERT_EN,
1222-
NAU8821_IRQ_INSERT_EN);
12231227
nau8821_setup_inserted_irq(nau8821);
12241228
} else {
12251229
dev_warn(nau8821->dev,
12261230
"Inserted IRQ fired but not connected\n");
12271231
nau8821_eject_jack(nau8821);
12281232
}
1233+
} else {
1234+
/* Clear the rightmost interrupt */
1235+
nau8821_irq_status_clear(regmap, active_irq);
12291236
}
12301237

1231-
if (!clear_irq)
1232-
clear_irq = active_irq;
1233-
/* clears the rightmost interruption */
1234-
regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq);
1235-
12361238
if (event_mask)
12371239
snd_soc_jack_report(nau8821->jack, event, event_mask);
12381240

0 commit comments

Comments
 (0)