* [PATCH 0/4] SDCA Improvements
@ 2026-02-23 9:54 Charles Keepax
2026-02-23 9:54 ` [PATCH 1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay Charles Keepax
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Charles Keepax @ 2026-02-23 9:54 UTC (permalink / raw)
To: broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
Another fairly mixed bag of small SDCA fixes/improvements. Fix one DisCo
property that was treated as mandatory but is actually not present in
the first version of the specification. Fix the counting of routes for
SU/GE DAPM widgets, this currently makes assumptions that are not
guaranteed to be true which can result in too many/few DAPM routes.
Then finally a couple improvements to the volume controls, simplify the
mapping between ALSA and SDCA volumes and pull the volume stuff back
into the SDCA code. It just wasn't sitting right with me that it was
being handled in the ASoC core given it is unlikely to ever see any
reuse outside of SDCA.
Thanks,
Charles
Charles Keepax (4):
ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay
ASoC: SDCA: Update counting of SU/GE DAPM routes
ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes
ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
include/sound/soc.h | 1 -
sound/soc/sdca/sdca_asoc.c | 114 ++++++++++++++++++++++++++++----
sound/soc/sdca/sdca_fdl.c | 5 --
sound/soc/sdca/sdca_functions.c | 6 +-
sound/soc/soc-ops.c | 63 +++---------------
5 files changed, 117 insertions(+), 72 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
@ 2026-02-23 9:54 ` Charles Keepax
2026-02-23 9:54 ` [PATCH 2/4] ASoC: SDCA: Update counting of SU/GE DAPM routes Charles Keepax
` (4 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Charles Keepax @ 2026-02-23 9:54 UTC (permalink / raw)
To: broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
Add a default value for the function reset timeout since version 1.0
of the SDCA specification doesn't actually include this property, it
was added later.
Fixes: 7b6be935e7ef ("ASoC: SDCA: Parse Function Reset max delay")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
sound/soc/sdca/sdca_fdl.c | 5 -----
sound/soc/sdca/sdca_functions.c | 6 +++++-
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c
index 07892bc3a44e6..994821a6df617 100644
--- a/sound/soc/sdca/sdca_fdl.c
+++ b/sound/soc/sdca/sdca_fdl.c
@@ -46,11 +46,6 @@ int sdca_reset_function(struct device *dev, struct sdca_function_data *function,
if (ret) // Allowed for function reset to not be implemented
return 0;
- if (!function->reset_max_delay) {
- dev_err(dev, "No reset delay specified in DisCo\n");
- return -EINVAL;
- }
-
/*
* Poll up to 16 times but no more than once per ms, these are just
* arbitrarily selected values, so may be fine tuned in future.
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 95b67bb904c31..a0aed95c76345 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -2167,8 +2167,12 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
ret = fwnode_property_read_u32(function_desc->node,
"mipi-sdca-function-reset-max-delay", &tmp);
- if (!ret)
+ if (ret || tmp == 0) {
+ dev_dbg(dev, "reset delay missing, defaulting to 100mS\n");
+ function->reset_max_delay = 100000;
+ } else {
function->reset_max_delay = tmp;
+ }
dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n",
function->desc->node, function->desc->name,
--
2.47.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/4] ASoC: SDCA: Update counting of SU/GE DAPM routes
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
2026-02-23 9:54 ` [PATCH 1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay Charles Keepax
@ 2026-02-23 9:54 ` Charles Keepax
2026-02-23 9:54 ` [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes Charles Keepax
` (3 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Charles Keepax @ 2026-02-23 9:54 UTC (permalink / raw)
To: broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
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")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.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 a0191e5a5a7dd..b6536eeecf58f 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -51,6 +51,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.
@@ -74,6 +93,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;
@@ -83,6 +103,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) {
@@ -96,6 +117,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;
}
@@ -104,7 +136,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]))
@@ -442,7 +475,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) {
@@ -478,11 +510,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.47.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
2026-02-23 9:54 ` [PATCH 1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay Charles Keepax
2026-02-23 9:54 ` [PATCH 2/4] ASoC: SDCA: Update counting of SU/GE DAPM routes Charles Keepax
@ 2026-02-23 9:54 ` Charles Keepax
2026-02-23 10:12 ` Richard Fitzgerald
2026-02-23 9:54 ` [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops Charles Keepax
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Charles Keepax @ 2026-02-23 9:54 UTC (permalink / raw)
To: broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
SDCA measures volumes in 256ths of a dB, whereas ALSA measures
volumes in 100ths of a dB. Currently the SDCA volume controls are
mapped to ALSA controls by mapping the step size and working out
the number of steps for this mapped step size. Due to quantization
of the step size this means the number of steps in the ALSA
control will rarely match the number of steps in the SDCA control,
leading to skipped values and multiple values that map to the
same volume. This is not a huge problem, the volume is still
increasing and the differences will be small but it is not really
desirable.
It is simpler and more accurate to count the number of steps based on
the SDCA volume levels. This gives a 1-to-1 mapping between control
values and register volumes. The TLV is based on a minimum and maximum
volume so still accurately specifies the volume range.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
sound/soc/sdca/sdca_asoc.c | 6 ++----
sound/soc/soc-ops.c | 12 ++----------
2 files changed, 4 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index b6536eeecf58f..e6f7c2778bec5 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -841,10 +841,8 @@ static int control_limit_kctl(struct device *dev,
tlv[2] = (min * 100) >> 8;
tlv[3] = (max * 100) >> 8;
- step = (step * 100) >> 8;
-
- mc->min = ((int)tlv[2] / step);
- mc->max = ((int)tlv[3] / step);
+ mc->min = min / step;
+ mc->max = max / step;
mc->shift = step;
mc->sign_bit = 15;
mc->sdca_q78 = 1;
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index f966d4e13c7fc..8ae6609ca9618 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -120,25 +120,17 @@ static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int re
return -EINVAL;
val = sign_extend32(val, mc->sign_bit);
- val = (((val * 100) >> 8) / (int)mc->shift);
- val -= mc->min;
- return val & mask;
+ return ((val / mc->shift) - mc->min) & mask;
}
static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
unsigned int mask, unsigned int shift, int max)
{
- unsigned int ret_val;
- int reg_val;
-
if (WARN_ON(!mc->shift))
return -EINVAL;
- reg_val = val + mc->min;
- ret_val = (int)((reg_val * mc->shift) << 8) / 100;
-
- return ret_val & mask;
+ return ((val + mc->min) * mc->shift) & mask;
}
static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
--
2.47.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
` (2 preceding siblings ...)
2026-02-23 9:54 ` [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes Charles Keepax
@ 2026-02-23 9:54 ` Charles Keepax
2026-02-23 11:43 ` Richard Fitzgerald
2026-02-24 13:55 ` Richard Fitzgerald
2026-02-24 10:58 ` [PATCH 0/4] SDCA Improvements Pierre-Louis Bossart
2026-02-27 6:37 ` Mark Brown
5 siblings, 2 replies; 12+ messages in thread
From: Charles Keepax @ 2026-02-23 9:54 UTC (permalink / raw)
To: broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
It is cleaner to keep the SDCA code contained and not update the core
code for things that are unlikely to see reuse outside of SDCA. Move the
Q7.8 volume helpers back into the SDCA core code.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
include/sound/soc.h | 1 -
sound/soc/sdca/sdca_asoc.c | 67 +++++++++++++++++++++++++++++++++++++-
sound/soc/soc-ops.c | 55 ++++++-------------------------
3 files changed, 76 insertions(+), 47 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7d8376c8e1bed..172bd68e1315f 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1239,7 +1239,6 @@ struct soc_mixer_control {
unsigned int sign_bit;
unsigned int invert:1;
unsigned int autodisable:1;
- unsigned int sdca_q78:1;
#ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj;
#endif
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index e6f7c2778bec5..a342a4e56717a 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -805,6 +805,70 @@ int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *funct
}
EXPORT_SYMBOL_NS(sdca_asoc_populate_dapm, "SND_SOC_SDCA");
+static int q78_write(struct snd_soc_component *component,
+ struct soc_mixer_control *mc,
+ unsigned int reg, const int val)
+{
+ unsigned int mask = GENMASK(mc->sign_bit, 0);
+ unsigned int reg_val;
+
+ if (val < 0 || val > mc->max - mc->min)
+ return -EINVAL;
+
+ reg_val = (val + mc->min) * mc->shift;
+
+ return snd_soc_component_update_bits(component, reg, mask, reg_val);
+}
+
+static int q78_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret;
+
+ ret = q78_write(component, mc, mc->reg, ucontrol->value.integer.value[0]);
+ if (ret < 0)
+ return ret;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ int err; /* Don't drop change flag */
+
+ err = q78_write(component, mc, mc->rreg, ucontrol->value.integer.value[1]);
+ if (err)
+ return err;
+ }
+
+ return ret;
+}
+
+static int q78_read(struct snd_soc_component *component,
+ struct soc_mixer_control *mc, unsigned int reg)
+{
+ unsigned int reg_val;
+ int val;
+
+ reg_val = snd_soc_component_read(component, reg);
+
+ val = (sign_extend32(reg_val, mc->sign_bit) / mc->shift) - mc->min;
+
+ return val & GENMASK(mc->sign_bit, 0);
+}
+
+static int q78_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = q78_read(component, mc, mc->reg);
+
+ if (snd_soc_volsw_is_stereo(mc))
+ ucontrol->value.integer.value[1] = q78_read(component, mc, mc->rreg);
+
+ return 0;
+}
+
static int control_limit_kctl(struct device *dev,
struct sdca_entity *entity,
struct sdca_control *control,
@@ -845,10 +909,11 @@ static int control_limit_kctl(struct device *dev,
mc->max = max / step;
mc->shift = step;
mc->sign_bit = 15;
- mc->sdca_q78 = 1;
kctl->tlv.p = tlv;
kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ kctl->get = q78_get_volsw;
+ kctl->put = q78_put_volsw;
return 0;
}
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 8ae6609ca9618..ed76ea81e6ec4 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -110,29 +110,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
-static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
- unsigned int mask, unsigned int shift, int max,
- bool sx)
-{
- int val = reg_val;
-
- if (WARN_ON(!mc->shift))
- return -EINVAL;
-
- val = sign_extend32(val, mc->sign_bit);
-
- return ((val / mc->shift) - mc->min) & mask;
-}
-
-static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
- unsigned int mask, unsigned int shift, int max)
-{
- if (WARN_ON(!mc->shift))
- return -EINVAL;
-
- return ((val + mc->min) * mc->shift) & mask;
-}
-
static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
unsigned int mask, unsigned int shift, int max,
bool sx)
@@ -226,26 +203,17 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct soc_mixer_control *mc, int mask, int max)
{
- unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int val1, val_mask;
unsigned int val2 = 0;
bool double_r = false;
int ret;
- if (mc->sdca_q78) {
- ctl_to_reg = sdca_soc_q78_ctl_to_reg;
- val_mask = mask;
- } else {
- ctl_to_reg = soc_mixer_ctl_to_reg;
- val_mask = mask << mc->shift;
- }
-
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
if (ret)
return ret;
- val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0],
+ val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0],
mask, mc->shift, max);
if (snd_soc_volsw_is_stereo(mc)) {
@@ -254,10 +222,14 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
return ret;
if (mc->reg == mc->rreg) {
- val1 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max);
+ val1 |= soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->rshift, max);
val_mask |= mask << mc->rshift;
} else {
- val2 = ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->shift, max);
+ val2 = soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->shift, max);
double_r = true;
}
}
@@ -281,28 +253,21 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct soc_mixer_control *mc, int mask, int max, bool sx)
{
- int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int,
- unsigned int, int, bool);
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg_val;
int val;
- if (mc->sdca_q78)
- reg_to_ctl = sdca_soc_q78_reg_to_ctl;
- else
- reg_to_ctl = soc_mixer_reg_to_ctl;
-
reg_val = snd_soc_component_read(component, mc->reg);
- val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
ucontrol->value.integer.value[0] = val;
if (snd_soc_volsw_is_stereo(mc)) {
if (mc->reg == mc->rreg) {
- val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx);
} else {
reg_val = snd_soc_component_read(component, mc->rreg);
- val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
}
ucontrol->value.integer.value[1] = val;
--
2.47.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes
2026-02-23 9:54 ` [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes Charles Keepax
@ 2026-02-23 10:12 ` Richard Fitzgerald
0 siblings, 0 replies; 12+ messages in thread
From: Richard Fitzgerald @ 2026-02-23 10:12 UTC (permalink / raw)
To: Charles Keepax, broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
On 23/02/2026 9:54 am, Charles Keepax wrote:
> SDCA measures volumes in 256ths of a dB, whereas ALSA measures
> volumes in 100ths of a dB. Currently the SDCA volume controls are
> mapped to ALSA controls by mapping the step size and working out
> the number of steps for this mapped step size. Due to quantization
> of the step size this means the number of steps in the ALSA
> control will rarely match the number of steps in the SDCA control,
> leading to skipped values and multiple values that map to the
> same volume. This is not a huge problem, the volume is still
> increasing and the differences will be small but it is not really
> desirable.
>
> It is simpler and more accurate to count the number of steps based on
> the SDCA volume levels. This gives a 1-to-1 mapping between control
> values and register volumes. The TLV is based on a minimum and maximum
> volume so still accurately specifies the volume range.
>
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
> sound/soc/sdca/sdca_asoc.c | 6 ++----
> sound/soc/soc-ops.c | 12 ++----------
> 2 files changed, 4 insertions(+), 14 deletions(-)
>
Tested-by: Richard Fitzgerald <rf@opensource.cirrus.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
2026-02-23 9:54 ` [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops Charles Keepax
@ 2026-02-23 11:43 ` Richard Fitzgerald
2026-02-24 13:54 ` Richard Fitzgerald
2026-02-24 13:55 ` Richard Fitzgerald
1 sibling, 1 reply; 12+ messages in thread
From: Richard Fitzgerald @ 2026-02-23 11:43 UTC (permalink / raw)
To: Charles Keepax, broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
On 23/02/2026 9:54 am, Charles Keepax wrote:
> It is cleaner to keep the SDCA code contained and not update the core
> code for things that are unlikely to see reuse outside of SDCA. Move the
> Q7.8 volume helpers back into the SDCA core code.
>
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
> include/sound/soc.h | 1 -
> sound/soc/sdca/sdca_asoc.c | 67 +++++++++++++++++++++++++++++++++++++-
> sound/soc/soc-ops.c | 55 ++++++-------------------------
> 3 files changed, 76 insertions(+), 47 deletions(-)
>
This needs a corresponding update to soc-ops-test.
With this patch I get 104 errors from soc-ops-test.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/4] SDCA Improvements
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
` (3 preceding siblings ...)
2026-02-23 9:54 ` [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops Charles Keepax
@ 2026-02-24 10:58 ` Pierre-Louis Bossart
2026-02-27 6:37 ` Mark Brown
5 siblings, 0 replies; 12+ messages in thread
From: Pierre-Louis Bossart @ 2026-02-24 10:58 UTC (permalink / raw)
To: Charles Keepax, broonie; +Cc: lgirdwood, yung-chuan.liao, linux-sound, patches
On 2/23/26 10:54, Charles Keepax wrote:
> Another fairly mixed bag of small SDCA fixes/improvements. Fix one DisCo
> property that was treated as mandatory but is actually not present in
> the first version of the specification. Fix the counting of routes for
> SU/GE DAPM widgets, this currently makes assumptions that are not
> guaranteed to be true which can result in too many/few DAPM routes.
Both valid changes indeed.
> Then finally a couple improvements to the volume controls, simplify the
> mapping between ALSA and SDCA volumes and pull the volume stuff back
> into the SDCA code. It just wasn't sitting right with me that it was
> being handled in the ASoC core given it is unlikely to ever see any
> reuse outside of SDCA.
Sounds good to me as well.
> Charles Keepax (4):
> ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay
> ASoC: SDCA: Update counting of SU/GE DAPM routes
> ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes
> ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
For the patchset,
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
>
> include/sound/soc.h | 1 -
> sound/soc/sdca/sdca_asoc.c | 114 ++++++++++++++++++++++++++++----
> sound/soc/sdca/sdca_fdl.c | 5 --
> sound/soc/sdca/sdca_functions.c | 6 +-
> sound/soc/soc-ops.c | 63 +++---------------
> 5 files changed, 117 insertions(+), 72 deletions(-)
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
2026-02-23 11:43 ` Richard Fitzgerald
@ 2026-02-24 13:54 ` Richard Fitzgerald
0 siblings, 0 replies; 12+ messages in thread
From: Richard Fitzgerald @ 2026-02-24 13:54 UTC (permalink / raw)
To: Charles Keepax, broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
On 23/02/2026 11:43 am, Richard Fitzgerald wrote:
> On 23/02/2026 9:54 am, Charles Keepax wrote:
>> It is cleaner to keep the SDCA code contained and not update the core
>> code for things that are unlikely to see reuse outside of SDCA. Move the
>> Q7.8 volume helpers back into the SDCA core code.
>>
>> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
>> ---
>> include/sound/soc.h | 1 -
>> sound/soc/sdca/sdca_asoc.c | 67 +++++++++++++++++++++++++++++++++++++-
>> sound/soc/soc-ops.c | 55 ++++++-------------------------
>> 3 files changed, 76 insertions(+), 47 deletions(-)
>>
> This needs a corresponding update to soc-ops-test.
> With this patch I get 104 errors from soc-ops-test.
Actually it doesn't need a test update. The test is correctly failing
because of an uninitialized variable left by removing the Q7.8 code.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
2026-02-23 9:54 ` [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops Charles Keepax
2026-02-23 11:43 ` Richard Fitzgerald
@ 2026-02-24 13:55 ` Richard Fitzgerald
2026-02-25 9:25 ` Charles Keepax
1 sibling, 1 reply; 12+ messages in thread
From: Richard Fitzgerald @ 2026-02-24 13:55 UTC (permalink / raw)
To: Charles Keepax, broonie
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
On 23/02/2026 9:54 am, Charles Keepax wrote:
> It is cleaner to keep the SDCA code contained and not update the core
> code for things that are unlikely to see reuse outside of SDCA. Move the
> Q7.8 volume helpers back into the SDCA core code.
>
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
> include/sound/soc.h | 1 -
> sound/soc/sdca/sdca_asoc.c | 67 +++++++++++++++++++++++++++++++++++++-
> sound/soc/soc-ops.c | 55 ++++++-------------------------
> 3 files changed, 76 insertions(+), 47 deletions(-)
>
> diff --git a/include/sound/soc.h b/include/sound/soc.h
> index 7d8376c8e1bed..172bd68e1315f 100644
> --- a/include/sound/soc.h
> +++ b/include/sound/soc.h
> @@ -1239,7 +1239,6 @@ struct soc_mixer_control {
> unsigned int sign_bit;
> unsigned int invert:1;
> unsigned int autodisable:1;
> - unsigned int sdca_q78:1;
> #ifdef CONFIG_SND_SOC_TOPOLOGY
> struct snd_soc_dobj dobj;
> #endif
> diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
> index e6f7c2778bec5..a342a4e56717a 100644
> --- a/sound/soc/sdca/sdca_asoc.c
> +++ b/sound/soc/sdca/sdca_asoc.c
> @@ -805,6 +805,70 @@ int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *funct
> }
> EXPORT_SYMBOL_NS(sdca_asoc_populate_dapm, "SND_SOC_SDCA");
>
> +static int q78_write(struct snd_soc_component *component,
> + struct soc_mixer_control *mc,
> + unsigned int reg, const int val)
> +{
> + unsigned int mask = GENMASK(mc->sign_bit, 0);
> + unsigned int reg_val;
> +
> + if (val < 0 || val > mc->max - mc->min)
> + return -EINVAL;
> +
> + reg_val = (val + mc->min) * mc->shift;
> +
> + return snd_soc_component_update_bits(component, reg, mask, reg_val);
> +}
> +
> +static int q78_put_volsw(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
> + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> + int ret;
> +
> + ret = q78_write(component, mc, mc->reg, ucontrol->value.integer.value[0]);
> + if (ret < 0)
> + return ret;
> +
> + if (snd_soc_volsw_is_stereo(mc)) {
> + int err; /* Don't drop change flag */
> +
> + err = q78_write(component, mc, mc->rreg, ucontrol->value.integer.value[1]);
> + if (err)
> + return err;
> + }
> +
> + return ret;
> +}
> +
> +static int q78_read(struct snd_soc_component *component,
> + struct soc_mixer_control *mc, unsigned int reg)
> +{
> + unsigned int reg_val;
> + int val;
> +
> + reg_val = snd_soc_component_read(component, reg);
> +
> + val = (sign_extend32(reg_val, mc->sign_bit) / mc->shift) - mc->min;
> +
> + return val & GENMASK(mc->sign_bit, 0);
> +}
> +
> +static int q78_get_volsw(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
> + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> +
> + ucontrol->value.integer.value[0] = q78_read(component, mc, mc->reg);
> +
> + if (snd_soc_volsw_is_stereo(mc))
> + ucontrol->value.integer.value[1] = q78_read(component, mc, mc->rreg);
> +
> + return 0;
> +}
> +
> static int control_limit_kctl(struct device *dev,
> struct sdca_entity *entity,
> struct sdca_control *control,
> @@ -845,10 +909,11 @@ static int control_limit_kctl(struct device *dev,
> mc->max = max / step;
> mc->shift = step;
> mc->sign_bit = 15;
> - mc->sdca_q78 = 1;
>
> kctl->tlv.p = tlv;
> kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
> + kctl->get = q78_get_volsw;
> + kctl->put = q78_put_volsw;
>
> return 0;
> }
> diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
> index 8ae6609ca9618..ed76ea81e6ec4 100644
> --- a/sound/soc/soc-ops.c
> +++ b/sound/soc/soc-ops.c
> @@ -110,29 +110,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
> }
> EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
>
> -static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
> - unsigned int mask, unsigned int shift, int max,
> - bool sx)
> -{
> - int val = reg_val;
> -
> - if (WARN_ON(!mc->shift))
> - return -EINVAL;
> -
> - val = sign_extend32(val, mc->sign_bit);
> -
> - return ((val / mc->shift) - mc->min) & mask;
> -}
> -
> -static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
> - unsigned int mask, unsigned int shift, int max)
> -{
> - if (WARN_ON(!mc->shift))
> - return -EINVAL;
> -
> - return ((val + mc->min) * mc->shift) & mask;
> -}
> -
> static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
> unsigned int mask, unsigned int shift, int max,
> bool sx)
> @@ -226,26 +203,17 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
> struct snd_ctl_elem_value *ucontrol,
> struct soc_mixer_control *mc, int mask, int max)
> {
> - unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
> struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> unsigned int val1, val_mask;
> unsigned int val2 = 0;
> bool double_r = false;
> int ret;
>
> - if (mc->sdca_q78) {
> - ctl_to_reg = sdca_soc_q78_ctl_to_reg;
> - val_mask = mask;
> - } else {
> - ctl_to_reg = soc_mixer_ctl_to_reg;
> - val_mask = mask << mc->shift;
Still need this line to initialize val_mask.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
2026-02-24 13:55 ` Richard Fitzgerald
@ 2026-02-25 9:25 ` Charles Keepax
0 siblings, 0 replies; 12+ messages in thread
From: Charles Keepax @ 2026-02-25 9:25 UTC (permalink / raw)
To: Richard Fitzgerald
Cc: broonie, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
linux-sound, patches
On Tue, Feb 24, 2026 at 01:55:16PM +0000, Richard Fitzgerald wrote:
> On 23/02/2026 9:54 am, Charles Keepax wrote:
> > It is cleaner to keep the SDCA code contained and not update the core
> > code for things that are unlikely to see reuse outside of SDCA. Move the
> > Q7.8 volume helpers back into the SDCA core code.
> >
> > Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> > ---
> > @@ -226,26 +203,17 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
> > struct snd_ctl_elem_value *ucontrol,
> > struct soc_mixer_control *mc, int mask, int max)
> > {
> > - unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
> > struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
> > unsigned int val1, val_mask;
> > unsigned int val2 = 0;
> > bool double_r = false;
> > int ret;
> > - if (mc->sdca_q78) {
> > - ctl_to_reg = sdca_soc_q78_ctl_to_reg;
> > - val_mask = mask;
> > - } else {
> > - ctl_to_reg = soc_mixer_ctl_to_reg;
> > - val_mask = mask << mc->shift;
> Still need this line to initialize val_mask.
Thanks Richard, will get that fixed up today.
Thanks,
Charles
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/4] SDCA Improvements
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
` (4 preceding siblings ...)
2026-02-24 10:58 ` [PATCH 0/4] SDCA Improvements Pierre-Louis Bossart
@ 2026-02-27 6:37 ` Mark Brown
5 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2026-02-27 6:37 UTC (permalink / raw)
To: Charles Keepax
Cc: lgirdwood, pierre-louis.bossart, yung-chuan.liao, linux-sound,
patches
On Mon, 23 Feb 2026 09:54:21 +0000, Charles Keepax wrote:
> Another fairly mixed bag of small SDCA fixes/improvements. Fix one DisCo
> property that was treated as mandatory but is actually not present in
> the first version of the specification. Fix the counting of routes for
> SU/GE DAPM widgets, this currently makes assumptions that are not
> guaranteed to be true which can result in too many/few DAPM routes.
>
> Then finally a couple improvements to the volume controls, simplify the
> mapping between ALSA and SDCA volumes and pull the volume stuff back
> into the SDCA code. It just wasn't sitting right with me that it was
> being handled in the ASoC core given it is unlikely to ever see any
> reuse outside of SDCA.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay
commit: 1bbbda5b178a1399339139eb3c326300008b72d6
[2/4] ASoC: SDCA: Update counting of SU/GE DAPM routes
commit: 1fb720d33eecdb9a90ee340b3000ba378d49f5ca
[3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes
commit: d4f7d5a9a0f963dc895c18084425ce332a80d3a8
[4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops
commit: 501efdcb3b3ab099fc0ce2f6e668b1c4095dd476
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-02-27 6:37 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-23 9:54 [PATCH 0/4] SDCA Improvements Charles Keepax
2026-02-23 9:54 ` [PATCH 1/4] ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay Charles Keepax
2026-02-23 9:54 ` [PATCH 2/4] ASoC: SDCA: Update counting of SU/GE DAPM routes Charles Keepax
2026-02-23 9:54 ` [PATCH 3/4] ASoC: SDCA: Improve mapping of Q7.8 SDCA volumes Charles Keepax
2026-02-23 10:12 ` Richard Fitzgerald
2026-02-23 9:54 ` [PATCH 4/4] ASoC: SDCA: Pull the Q7.8 volume helpers out of soc-ops Charles Keepax
2026-02-23 11:43 ` Richard Fitzgerald
2026-02-24 13:54 ` Richard Fitzgerald
2026-02-24 13:55 ` Richard Fitzgerald
2026-02-25 9:25 ` Charles Keepax
2026-02-24 10:58 ` [PATCH 0/4] SDCA Improvements Pierre-Louis Bossart
2026-02-27 6:37 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox