diff options
author | Hans de Goede <hdegoede@redhat.com> | 2024-10-24 23:56:12 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2024-10-25 00:50:13 +0100 |
commit | 032532f91a1d06d0750f16c49a9698ef5374a68f (patch) | |
tree | ea7aa41a62dcd8d67a8e53be7f9c9b4e92497261 /sound/soc | |
parent | db7e59e6a39a4d3d54ca8197c796557e6d480b0d (diff) |
ASoC: codecs: rt5640: Always disable IRQs from rt5640_cancel_work()
Disable IRQs from rt5640_cancel_work(), this fixes a crash caused by
the IRQ never getting freed when the driver is unbound from the i2c_client
with jack-detection active:
[ 193.138780] rt5640 i2c-rt5640: ASoC: unknown pin LDO2
[ 193.138830] rt5640 i2c-rt5640: ASoC: unknown pin MICBIAS1
[ 193.671218] BUG: kernel NULL pointer dereference, address: 0000000000000078
[ 193.671239] #PF: supervisor read access in kernel mode
[ 193.671248] #PF: error_code(0x0000) - not-present page
...
[ 193.671531] ? asm_exc_page_fault+0x22/0x30
[ 193.671551] ? rt5640_jack_inserted+0x10/0x80 [snd_soc_rt5640]
[ 193.671574] rt5640_detect_headset+0x93/0x130 [snd_soc_rt5640]
[ 193.671596] rt5640_jack_work+0x93/0x355 [snd_soc_rt5640]
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://patch.msgid.link/20241024215612.92147-1-hdegoede@redhat.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/rt5640.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 16f3425a3e35..855139348edb 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2419,10 +2419,20 @@ static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data) return IRQ_HANDLED; } -static void rt5640_cancel_work(void *data) +static void rt5640_disable_irq_and_cancel_work(void *data) { struct rt5640_priv *rt5640 = data; + if (rt5640->jd_gpio_irq_requested) { + free_irq(rt5640->jd_gpio_irq, rt5640); + rt5640->jd_gpio_irq_requested = false; + } + + if (rt5640->irq_requested) { + free_irq(rt5640->irq, rt5640); + rt5640->irq_requested = false; + } + cancel_delayed_work_sync(&rt5640->jack_work); cancel_delayed_work_sync(&rt5640->bp_work); } @@ -2463,13 +2473,7 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) if (!rt5640->jack) return; - if (rt5640->jd_gpio_irq_requested) - free_irq(rt5640->jd_gpio_irq, rt5640); - - if (rt5640->irq_requested) - free_irq(rt5640->irq, rt5640); - - rt5640_cancel_work(rt5640); + rt5640_disable_irq_and_cancel_work(rt5640); if (rt5640->jack->status & SND_JACK_MICROPHONE) { rt5640_disable_micbias1_ovcd_irq(component); @@ -2477,8 +2481,6 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); } - rt5640->jd_gpio_irq_requested = false; - rt5640->irq_requested = false; rt5640->jd_gpio = NULL; rt5640->jack = NULL; } @@ -2798,7 +2800,8 @@ static int rt5640_suspend(struct snd_soc_component *component) if (rt5640->jack) { /* disable jack interrupts during system suspend */ disable_irq(rt5640->irq); - rt5640_cancel_work(rt5640); + cancel_delayed_work_sync(&rt5640->jack_work); + cancel_delayed_work_sync(&rt5640->bp_work); } snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); @@ -3032,7 +3035,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work); /* Make sure work is stopped on probe-error / remove */ - ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640); + ret = devm_add_action_or_reset(&i2c->dev, rt5640_disable_irq_and_cancel_work, rt5640); if (ret) return ret; |