From: Charles Keepax <ckeepax@opensource.cirrus.com>
To: broonie@kernel.org
Cc: lgirdwood@gmail.com, yung-chuan.liao@linux.intel.com,
pierre-louis.bossart@linux.dev, linux-sound@vger.kernel.org,
linux-kernel@vger.kernel.org, patches@opensource.cirrus.com
Subject: [PATCH v2 3/3] ASoC: SDCA: Switch to fixup_controls callback for IRQ registration
Date: Wed, 15 Jul 2026 17:29:18 +0100 [thread overview]
Message-ID: <20260715162918.1898396-4-ckeepax@opensource.cirrus.com> (raw)
In-Reply-To: <20260715162918.1898396-1-ckeepax@opensource.cirrus.com>
Currently there are some race conditions around the boot of SDCA
jack detection. The core creates DAPM widgets/routes quite a
long time before it creates the associated ALSA control, and
the jack detection IRQ is currently registered in component
probe. At the time of component probe, the DAPM widgets exist,
shortly after this the DAPM routes are added. At the time the DAPM
routes are added the register value for the control is checked
and the appropriate path is connected. The existing handling
in the SDCA jack IRQ handles the case the control doesn't exist
and updates the registers directly, which works until the DAPM
routes are added. After the routes are added the DAPM graph has
already set connected on a particular DAPM path, which will not
be updated until an IRQ is received when the control is present.
Thus those updated are usually not reflected in the resulting
DAPM graph which can lead to the audio path being erroneously
powered on/off.
Switch to the new fixup_controls callback to register the
IRQs, this is guaranteed to run after all the controls have
been created. Which means we can avoid the aforementioned race
condition and as a bonus no longer need to concern ourselves
with a case where the IRQ handler runs and the ALSA control
is unavailable.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
Changes since v1:
- Remove the bus remove callback since all the IRQs are freed in
component remove and the memory is devm managed.
sound/soc/sdca/sdca_class_function.c | 12 ++------
sound/soc/sdca/sdca_jack.c | 44 ++++++++++++----------------
2 files changed, 21 insertions(+), 35 deletions(-)
diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c
index 1496a15f7d2ac..32cada9e369cb 100644
--- a/sound/soc/sdca/sdca_class_function.c
+++ b/sound/soc/sdca/sdca_class_function.c
@@ -191,7 +191,7 @@ static const struct snd_soc_dai_ops class_function_sdw_ops = {
.hw_free = class_function_sdw_remove_peripheral,
};
-static int class_function_component_probe(struct snd_soc_component *component)
+static int class_function_component_fixup_controls(struct snd_soc_component *component)
{
struct class_function_drv *drv = snd_soc_component_get_drvdata(component);
struct sdca_class_drv *core = drv->core;
@@ -217,7 +217,7 @@ static int class_function_set_jack(struct snd_soc_component *component,
}
static const struct snd_soc_component_driver class_function_component_drv = {
- .probe = class_function_component_probe,
+ .fixup_controls = class_function_component_fixup_controls,
.remove = class_function_component_remove,
.endianness = 1,
};
@@ -404,13 +404,6 @@ static int class_function_probe(struct auxiliary_device *auxdev,
return 0;
}
-static void class_function_remove(struct auxiliary_device *auxdev)
-{
- struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
-
- sdca_irq_cleanup(drv->dev, drv->function, drv->core->irq_info);
-}
-
static int class_function_runtime_suspend(struct device *dev)
{
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
@@ -563,7 +556,6 @@ static struct auxiliary_driver class_function_drv = {
},
.probe = class_function_probe,
- .remove = class_function_remove,
.id_table = class_function_id_table
};
module_auxiliary_driver(class_function_drv);
diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c
index ae9636622a840..2ac74b9826736 100644
--- a/sound/soc/sdca/sdca_jack.c
+++ b/sound/soc/sdca/sdca_jack.c
@@ -41,6 +41,7 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
struct jack_state *state = interrupt->priv;
struct snd_kcontrol *kctl = state->kctl;
struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL;
+ struct soc_enum *soc_enum;
unsigned int reg, val;
int ret;
@@ -55,10 +56,12 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
return -ENOMEM;
kctl = snd_soc_component_get_kcontrol(component, name);
- if (!kctl)
- dev_dbg(dev, "control not found: %s\n", name);
- else
- state->kctl = kctl;
+ if (!kctl) {
+ dev_err(dev, "control not found: %s\n", name);
+ return -ENODEV;
+ }
+
+ state->kctl = kctl;
}
reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
@@ -96,30 +99,21 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
dev_dbg(dev, "%s: %#x\n", interrupt->name, val);
- if (kctl) {
- struct soc_enum *soc_enum = (struct soc_enum *)kctl->private_value;
-
- ucontrol = kzalloc_obj(*ucontrol);
- if (!ucontrol)
- return -ENOMEM;
-
- ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
+ ucontrol = kzalloc_obj(*ucontrol);
+ if (!ucontrol)
+ return -ENOMEM;
- ret = snd_soc_dapm_put_enum_double(kctl, ucontrol);
- if (ret < 0) {
- dev_err(dev, "failed to update selected mode: %d\n", ret);
- return ret;
- }
+ soc_enum = (struct soc_enum *)kctl->private_value;
+ ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
- snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- } else {
- ret = regmap_write(interrupt->function_regmap, reg, val);
- if (ret) {
- dev_err(dev, "failed to write selected mode: %d\n", ret);
- return ret;
- }
+ ret = snd_soc_dapm_put_enum_double(kctl, ucontrol);
+ if (ret < 0) {
+ dev_err(dev, "failed to update selected mode: %d\n", ret);
+ return ret;
}
+ snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+
return sdca_jack_report(interrupt);
}
EXPORT_SYMBOL_NS_GPL(sdca_jack_process, "SND_SOC_SDCA");
@@ -192,7 +186,7 @@ int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *ja
struct sdca_control_range *range;
struct jack_state *jack_state;
- if (!interrupt->irq)
+ if (!interrupt->dev)
continue;
switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
--
2.47.3
next prev parent reply other threads:[~2026-07-15 16:29 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 16:29 [PATCH v2 0/3] Fix races on creation of SDCA jack detection Charles Keepax
2026-07-15 16:29 ` [PATCH v2 1/3] ASoC: Add a component fixup_controls callback Charles Keepax
2026-07-15 16:29 ` [PATCH v2 2/3] ASoC: SDCA: Populate IRQ data earlier Charles Keepax
2026-07-15 16:29 ` Charles Keepax [this message]
2026-07-16 9:32 ` [PATCH v2 3/3] ASoC: SDCA: Switch to fixup_controls callback for IRQ registration Charles Keepax
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260715162918.1898396-4-ckeepax@opensource.cirrus.com \
--to=ckeepax@opensource.cirrus.com \
--cc=broonie@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=patches@opensource.cirrus.com \
--cc=pierre-louis.bossart@linux.dev \
--cc=yung-chuan.liao@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox