[PATCH v3 2/4] ASoC: SDCA: Populate IRQ data earlier
From: Charles Keepax
Date: Thu Jul 16 2026 - 10:41:12 EST
Currently, the IRQ data (attached Entity/Control/etc) is populated
as the IRQ is requested. However, this can cause issues as
occasionally the setup process wants to access specifics of
an IRQ before the IRQ is actually enabled. To facilitate this
cache all the IRQ data during sdca_irq_populate_early() and make
sdca_irq_populate() simply request the outstanding IRQs. This
also has the advantage that sdca_irq_populate() can now just
iterate through the IRQ array which is much smaller/faster than
going through every Entity in the Function for Controls.
Signed-off-by: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
---
No changes since v2.
include/sound/sdca_interrupts.h | 2 +
sound/soc/sdca/sdca_interrupts.c | 98 ++++++++++++--------------------
2 files changed, 38 insertions(+), 62 deletions(-)
diff --git a/include/sound/sdca_interrupts.h b/include/sound/sdca_interrupts.h
index a515cc3df0971..20ff5eac34eaa 100644
--- a/include/sound/sdca_interrupts.h
+++ b/include/sound/sdca_interrupts.h
@@ -30,6 +30,7 @@ struct sdca_function_data;
* @function: Pointer to the Function that the interrupt is associated with.
* @entity: Pointer to the Entity that the interrupt is associated with.
* @control: Pointer to the Control that the interrupt is associated with.
+ * @handler: Handler function to be called for the IRQ.
* @priv: Pointer to private data for use by the handler.
* @irq: IRQ number allocated to this interrupt, also used internally to track
* the IRQ being assigned.
@@ -44,6 +45,7 @@ struct sdca_interrupt {
struct sdca_function_data *function;
struct sdca_entity *entity;
struct sdca_control *control;
+ irq_handler_t handler;
void *priv;
diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
index 4539a52a8e32b..6bbe65ac3d2f0 100644
--- a/sound/soc/sdca/sdca_interrupts.c
+++ b/sound/soc/sdca/sdca_interrupts.c
@@ -375,7 +375,7 @@ int sdca_irq_data_populate(struct device *dev, struct regmap *regmap,
if (!dev)
return -ENODEV;
- name = kasprintf(GFP_KERNEL, "%s %s", entity->label, control->label);
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", entity->label, control->label);
if (!name)
return -ENOMEM;
@@ -448,21 +448,34 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
else if (!interrupt)
continue;
+ ret = sdca_irq_data_populate(dev, regmap, NULL, function,
+ entity, control, interrupt);
+ if (ret)
+ return ret;
+
+ interrupt->handler = base_handler;
+
switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
- case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
- ret = sdca_irq_data_populate(dev, regmap, NULL,
- function, entity,
- control, interrupt);
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
+ interrupt->handler = function_status_handler;
+ break;
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ ret = sdca_jack_alloc_state(interrupt);
if (ret)
return ret;
+ interrupt->handler = detected_mode_handler;
+ break;
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
ret = sdca_fdl_alloc_state(interrupt);
if (ret)
return ret;
+ interrupt->handler = fdl_owner_handler;
+
ret = sdca_irq_request_locked(dev, info, irq,
interrupt->name,
- fdl_owner_handler,
+ interrupt->handler,
interrupt);
if (ret) {
dev_err(dev, "failed to request irq %s: %d\n",
@@ -470,6 +483,9 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
return ret;
}
break;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ interrupt->handler = hid_handler;
+ break;
default:
break;
}
@@ -495,66 +511,26 @@ int sdca_irq_populate(struct sdca_function_data *function,
struct sdca_interrupt_info *info)
{
struct device *dev = component->dev;
- int i, j;
+ int i, ret;
guard(mutex)(&info->irq_lock);
- for (i = 0; i < function->num_entities; i++) {
- struct sdca_entity *entity = &function->entities[i];
-
- for (j = 0; j < entity->num_controls; j++) {
- struct sdca_control *control = &entity->controls[j];
- int irq = control->interrupt_position;
- struct sdca_interrupt *interrupt;
- irq_handler_t handler;
- int ret;
-
- interrupt = get_interrupt_data(dev, irq, info);
- if (IS_ERR(interrupt))
- return PTR_ERR(interrupt);
- else if (!interrupt)
- continue;
-
- ret = sdca_irq_data_populate(dev, NULL, component,
- function, entity, control,
- interrupt);
- if (ret)
- return ret;
-
- handler = base_handler;
-
- switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
- case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
- handler = function_status_handler;
- break;
- case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
- ret = sdca_jack_alloc_state(interrupt);
- if (ret)
- return ret;
+ for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
+ struct sdca_interrupt *interrupt = &info->irqs[i];
+ int irq;
- handler = detected_mode_handler;
- break;
- case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
- ret = sdca_fdl_alloc_state(interrupt);
- if (ret)
- return ret;
+ if (interrupt->function != function || interrupt->irq)
+ continue;
- handler = fdl_owner_handler;
- break;
- case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
- handler = hid_handler;
- break;
- default:
- break;
- }
+ interrupt->component = component;
- ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
- handler, interrupt);
- if (ret) {
- dev_err(dev, "failed to request irq %s: %d\n",
- interrupt->name, ret);
- return ret;
- }
+ irq = interrupt->control->interrupt_position;
+ ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
+ interrupt->handler, interrupt);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n",
+ interrupt->name, ret);
+ return ret;
}
}
@@ -585,8 +561,6 @@ void sdca_irq_cleanup(struct device *dev,
continue;
sdca_irq_free_locked(dev, info, i, interrupt->name, interrupt);
-
- kfree(interrupt->name);
}
}
EXPORT_SYMBOL_NS_GPL(sdca_irq_cleanup, "SND_SOC_SDCA");
--
2.47.3