mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
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>
This commit is contained in:
parent
db7e59e6a3
commit
032532f91a
@ -2419,10 +2419,20 @@ static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data)
|
|||||||
return IRQ_HANDLED;
|
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;
|
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->jack_work);
|
||||||
cancel_delayed_work_sync(&rt5640->bp_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)
|
if (!rt5640->jack)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (rt5640->jd_gpio_irq_requested)
|
rt5640_disable_irq_and_cancel_work(rt5640);
|
||||||
free_irq(rt5640->jd_gpio_irq, rt5640);
|
|
||||||
|
|
||||||
if (rt5640->irq_requested)
|
|
||||||
free_irq(rt5640->irq, rt5640);
|
|
||||||
|
|
||||||
rt5640_cancel_work(rt5640);
|
|
||||||
|
|
||||||
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
|
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
|
||||||
rt5640_disable_micbias1_ovcd_irq(component);
|
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);
|
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->jd_gpio = NULL;
|
||||||
rt5640->jack = NULL;
|
rt5640->jack = NULL;
|
||||||
}
|
}
|
||||||
@ -2798,7 +2800,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
|
|||||||
if (rt5640->jack) {
|
if (rt5640->jack) {
|
||||||
/* disable jack interrupts during system suspend */
|
/* disable jack interrupts during system suspend */
|
||||||
disable_irq(rt5640->irq);
|
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);
|
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);
|
INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work);
|
||||||
|
|
||||||
/* Make sure work is stopped on probe-error / remove */
|
/* 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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user