From: Tristan Madani The rt5668 codec initializes two delayed works (jack_detect_work, jd_check_work) but neither is cancelled during component removal. If the card is unbound while these works are pending, they fire on freed resources when snd_soc_jack_report() dereferences the cleared card pointer. Track successful IRQ acquisition with a flag so that disable_irq() only quiesces a line this driver actually owns. On component remove, disable the IRQ to stop the handler from rescheduling work, then drain both delayed works before resetting the codec. On the next component probe (card rebind), re-enable the IRQ to restore jack detection. Fixes: d59fb2856223 ("ASoC: rt5668: add rt5668B codec driver") Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani --- sound/soc/codecs/rt5668.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 4154bad276101..01b14c62fde7f 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -62,6 +62,8 @@ struct rt5668_priv { int pll_out; int jack_type; + bool irq_acquired; + bool irq_disabled; }; static const struct reg_default rt5668_reg[] = { @@ -2213,6 +2215,12 @@ static int rt5668_set_bias_level(struct snd_soc_component *component, static int rt5668_probe(struct snd_soc_component *component) { struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component); + struct i2c_client *i2c = to_i2c_client(component->dev); + + if (rt5668->irq_disabled) { + enable_irq(i2c->irq); + rt5668->irq_disabled = false; + } rt5668->component = component; @@ -2222,7 +2230,15 @@ static int rt5668_probe(struct snd_soc_component *component) static void rt5668_remove(struct snd_soc_component *component) { struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component); + struct i2c_client *i2c = to_i2c_client(component->dev); + if (rt5668->irq_acquired) { + disable_irq(i2c->irq); + rt5668->irq_disabled = true; + } + + cancel_delayed_work_sync(&rt5668->jack_detect_work); + cancel_delayed_work_sync(&rt5668->jd_check_work); rt5668_reset(rt5668->regmap); } @@ -2531,7 +2547,9 @@ static int rt5668_i2c_probe(struct i2c_client *i2c) ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rt5668_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5668", rt5668); - if (ret) + if (!ret) + rt5668->irq_acquired = true; + else dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret); } -- 2.47.3