[SRU][R][PATCH 2/7] ASoC: SDCA: Update counting of SU/GE DAPM routes
Chris Chiu
chris.chiu at canonical.com
Tue Mar 17 03:44:33 UTC 2026
From: Charles Keepax <ckeepax at opensource.cirrus.com>
BugLink: https://bugs.launchpad.net/bugs/2143902
Device Layer Selector Unit's are controlled by a Group Entity control
rather than by the host directly. For the purposes of the ASoC class
driver the number of input routes to the SU is controlled by the number
of options within the Group Entity Selected Mode Control. ie. One valid
DAPM route for each valid route defined in the Group Entity.
Currently the code assumes that a Device Layer SU will have a number of
routes equal to the number of potential sources for the SU. ie. it
counts the routes using the SU, but then creates the routes using the
GE. However, this isn't actually true, it is perfectly allowed for the
GE to only define options for some of the potential sources of the SU.o
In such a case the number of routes return will not match those created,
leading to either an overflow of the routes array or undefined routes to
be past to the ASoC core, both of which generally lead to the sound card
failing to probe.
Update the handling for the counting of routes to count the connected
routes on the GE itself and then ignore the source routes on the SU.
This makes it match the logic generating the routes and ensuring that
both remain in sync.
Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo")
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.dev>
Signed-off-by: Charles Keepax <ckeepax at opensource.cirrus.com>
Link: https://patch.msgid.link/20260225140118.402695-3-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie at kernel.org>
(cherry picked from commit 1fb720d33eecdb9a90ee340b3000ba378d49f5ca)
Signed-off-by: Chris Chiu <chris.chiu at canonical.com>
---
sound/soc/sdca/sdca_asoc.c | 41 +++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index 65e87de1563b..49cbf38b7adb 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -50,6 +50,25 @@ static bool readonly_control(struct sdca_control *control)
return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO;
}
+static int ge_count_routes(struct sdca_entity *entity)
+{
+ int count = 0;
+ int i, j;
+
+ for (i = 0; i < entity->ge.num_modes; i++) {
+ struct sdca_ge_mode *mode = &entity->ge.modes[i];
+
+ for (j = 0; j < mode->num_controls; j++) {
+ struct sdca_ge_control *affected = &mode->controls[j];
+
+ if (affected->sel != SDCA_CTL_SU_SELECTOR || affected->val)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/**
* sdca_asoc_count_component - count the various component parts
* @dev: Pointer to the device against which allocations will be done.
@@ -73,6 +92,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
int *num_widgets, int *num_routes, int *num_controls,
int *num_dais)
{
+ struct sdca_control *control;
int i, j;
*num_widgets = function->num_entities - 1;
@@ -82,6 +102,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
for (i = 0; i < function->num_entities - 1; i++) {
struct sdca_entity *entity = &function->entities[i];
+ bool skip_primary_routes = false;
/* Add supply/DAI widget connections */
switch (entity->type) {
@@ -95,6 +116,17 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
case SDCA_ENTITY_TYPE_PDE:
*num_routes += entity->pde.num_managed;
break;
+ case SDCA_ENTITY_TYPE_GE:
+ *num_routes += ge_count_routes(entity);
+ skip_primary_routes = true;
+ break;
+ case SDCA_ENTITY_TYPE_SU:
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR);
+ if (!control)
+ return -EINVAL;
+
+ skip_primary_routes = (control->layers == SDCA_ACCESS_LAYER_DEVICE);
+ break;
default:
break;
}
@@ -103,7 +135,8 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
(*num_routes)++;
/* Add primary entity connections from DisCo */
- *num_routes += entity->num_sources;
+ if (!skip_primary_routes)
+ *num_routes += entity->num_sources;
for (j = 0; j < entity->num_controls; j++) {
if (exported_control(entity, &entity->controls[j]))
@@ -406,7 +439,6 @@ static int entity_parse_su_device(struct device *dev,
struct snd_soc_dapm_route **route)
{
struct sdca_control_range *range;
- int num_routes = 0;
int i, j;
if (!entity->group) {
@@ -442,11 +474,6 @@ static int entity_parse_su_device(struct device *dev,
return -EINVAL;
}
- if (++num_routes > entity->num_sources) {
- dev_err(dev, "%s: too many input routes\n", entity->label);
- return -EINVAL;
- }
-
term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX,
mode->val, SDCA_SELECTED_MODE_TERM_TYPE);
if (!term) {
--
2.43.0
More information about the kernel-team
mailing list