[PATCH v4 7/7] ASoC: SDCA: Move kcontrol search out of IRQ

From: Charles Keepax

Date: Tue Jul 21 2026 - 10:43:07 EST


Now that the IRQs are always registered after all the ALSA
controls are created it is possible to search for the control
at the point the IRQ is requested. Move the control search out
of the IRQ handler and do it at IRQ request time.

This also fixes a potential issue when the card was torn down
and reprobed without destroying the codec device, the kctl
pointer stored by the IRQ handler would not be updated to the
new control on the second probe.

Signed-off-by: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
---

New since v3.

include/sound/sdca_jack.h | 1 +
sound/soc/sdca/sdca_interrupts.c | 12 +++++++++
sound/soc/sdca/sdca_jack.c | 43 +++++++++++++++++++-------------
3 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/include/sound/sdca_jack.h b/include/sound/sdca_jack.h
index 59de40b7d7d01..871ba2d8146a3 100644
--- a/include/sound/sdca_jack.h
+++ b/include/sound/sdca_jack.h
@@ -28,6 +28,7 @@ struct jack_state {
};

int sdca_jack_alloc_state(struct sdca_interrupt *interrupt);
+int sdca_jack_init_state(struct sdca_interrupt *interrupt);
void sdca_jack_free_state(struct sdca_interrupt *interrupt);

int sdca_jack_process(struct sdca_interrupt *interrupt);
diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
index 6f0d8c0fe622d..42fbd3af8a754 100644
--- a/sound/soc/sdca/sdca_interrupts.c
+++ b/sound/soc/sdca/sdca_interrupts.c
@@ -521,6 +521,8 @@ int sdca_irq_populate(struct sdca_function_data *function,

for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
struct sdca_interrupt *interrupt = &info->irqs[i];
+ struct sdca_control *control = interrupt->control;
+ struct sdca_entity *entity = interrupt->entity;
int irq;

if (interrupt->function != function || interrupt->irq)
@@ -528,6 +530,16 @@ int sdca_irq_populate(struct sdca_function_data *function,

interrupt->component = component;

+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ ret = sdca_jack_init_state(interrupt);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
irq = interrupt->control->interrupt_position;
ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
interrupt->handler, interrupt);
diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c
index 3c84d17244a28..73f8067906a90 100644
--- a/sound/soc/sdca/sdca_jack.c
+++ b/sound/soc/sdca/sdca_jack.c
@@ -47,23 +47,6 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)

guard(rwsem_write)(rwsem);

- if (!kctl) {
- const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
- interrupt->entity->label,
- SDCA_CTL_SELECTED_MODE_NAME);
-
- if (!name)
- return -ENOMEM;
-
- kctl = snd_soc_component_get_kcontrol(component, name);
- 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,
interrupt->control->sel, 0);

@@ -148,6 +131,32 @@ void sdca_jack_free_state(struct sdca_interrupt *interrupt)
}
EXPORT_SYMBOL_NS_GPL(sdca_jack_free_state, "SND_SOC_SDCA");

+/**
+ * sdca_jack_init_state - Initialise transient state for a jack interrupt
+ * @interrupt: SDCA interrupt structure.
+ *
+ * Return: Zero on success or a negative error code.
+ */
+int sdca_jack_init_state(struct sdca_interrupt *interrupt)
+{
+ struct jack_state *jack_state = interrupt->priv;
+ const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
+ interrupt->entity->label,
+ SDCA_CTL_SELECTED_MODE_NAME);
+
+ if (!name)
+ return -ENOMEM;
+
+ jack_state->kctl = snd_soc_component_get_kcontrol(interrupt->component, name);
+ if (!jack_state->kctl) {
+ dev_err(interrupt->dev, "control not found: %s\n", name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_jack_init_state, "SND_SOC_SDCA");
+
static int type_get_mask(enum sdca_terminal_type type)
{
switch (type) {
--
2.47.3