]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: SDCA: Move kcontrol search out of IRQ
authorCharles Keepax <ckeepax@opensource.cirrus.com>
Tue, 21 Jul 2026 14:36:36 +0000 (15:36 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 27 Jul 2026 17:47:09 +0000 (18:47 +0100)
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@opensource.cirrus.com>
Link: https://patch.msgid.link/20260721143636.361814-8-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sdca_jack.h
sound/soc/sdca/sdca_interrupts.c
sound/soc/sdca/sdca_jack.c

index 59de40b7d7d01d3eab717b5bd6f1835e2d6ad613..871ba2d8146a397c24240d455f6d02de71926dbc 100644 (file)
@@ -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);
index 6f0d8c0fe622d956d72159e3501d36892e995dcb..42fbd3af8a754ca76eed1850a559f0f53e22fd48 100644 (file)
@@ -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);
index 3c84d17244a2842c8b9bdad74d7ac1228d33f81d..73f8067906a90efb58346a12325fb8b8fd47dd53 100644 (file)
@@ -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) {