From 9a773d9d21fa909e8babbe11e93c811cf1a6d22d Mon Sep 17 00:00:00 2001 From: Hongyan Xu Date: Mon, 28 Sep 2026 21:40:54 +0800 Subject: [PATCH] ASoC: mt6359-accdet: manage private workqueues with devres The threaded jack-detect interrupts queue work on two private workqueues. Neither queue is destroyed on device removal, so queued callbacks can retain pointers to devm-allocated state after it is released. Probe error paths also leak the queues. Create and initialize both workqueues before requesting interrupts, then add a managed cleanup action. Since the managed IRQs are acquired afterwards, devres releases and synchronizes them before draining and destroying the workqueues on both removal and probe failure. Fixes: eef07b9e0925 ("ASoC: mediatek: mt6359: add MT6359 accdet jack driver") Signed-off-by: Hongyan Xu Link: https://patch.msgid.link/20260928134054.312-1-getshell@seu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359-accdet.c | 50 ++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index e1190c644021..54ec1c6bd64b 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -914,6 +914,14 @@ int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(mt6359_accdet_enable_jack_detect); +static void mt6359_accdet_destroy_workqueues(void *data) +{ + struct mt6359_accdet *priv = data; + + destroy_workqueue(priv->jd_workqueue); + destroy_workqueue(priv->accdet_workqueue); +} + static int mt6359_accdet_probe(struct platform_device *pdev) { struct mt6359_accdet *priv; @@ -955,6 +963,26 @@ static int mt6359_accdet_probe(struct platform_device *pdev) } mutex_init(&priv->res_lock); + priv->accdet_workqueue = create_singlethread_workqueue("accdet"); + INIT_WORK(&priv->accdet_work, mt6359_accdet_work); + if (!priv->accdet_workqueue) { + dev_err(&pdev->dev, "Failed to create accdet workqueue\n"); + return -ENOMEM; + } + + priv->jd_workqueue = create_singlethread_workqueue("mt6359_accdet_jd"); + INIT_WORK(&priv->jd_work, mt6359_accdet_jd_work); + if (!priv->jd_workqueue) { + dev_err(&pdev->dev, "Failed to create jack detect workqueue\n"); + destroy_workqueue(priv->accdet_workqueue); + return -ENOMEM; + } + + ret = devm_add_action_or_reset(&pdev->dev, + mt6359_accdet_destroy_workqueues, priv); + if (ret) + return ret; + priv->accdet_irq = platform_get_irq(pdev, 0); if (priv->accdet_irq >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq, @@ -1000,22 +1028,6 @@ static int mt6359_accdet_probe(struct platform_device *pdev) } } - priv->accdet_workqueue = create_singlethread_workqueue("accdet"); - INIT_WORK(&priv->accdet_work, mt6359_accdet_work); - if (!priv->accdet_workqueue) { - dev_err(&pdev->dev, "Failed to create accdet workqueue\n"); - ret = -1; - goto err_accdet_wq; - } - - priv->jd_workqueue = create_singlethread_workqueue("mt6359_accdet_jd"); - INIT_WORK(&priv->jd_work, mt6359_accdet_jd_work); - if (!priv->jd_workqueue) { - dev_err(&pdev->dev, "Failed to create jack detect workqueue\n"); - ret = -1; - goto err_eint_wq; - } - platform_set_drvdata(pdev, priv); ret = devm_snd_soc_register_component(&pdev->dev, &mt6359_accdet_soc_driver, @@ -1034,12 +1046,6 @@ static int mt6359_accdet_probe(struct platform_device *pdev) mt6359_accdet_jack_report(priv); return 0; - -err_eint_wq: - destroy_workqueue(priv->accdet_workqueue); -err_accdet_wq: - dev_err(&pdev->dev, "%s error. now exit.!\n", __func__); - return ret; } static struct platform_driver mt6359_accdet_driver = {