* [PATCH v2 1/3] ASoC: ops: Factor out common code from get callbacks
2025-03-19 17:51 [PATCH v2 0/3] Tidy up ASoC control get and put handlers Charles Keepax
@ 2025-03-19 17:51 ` Charles Keepax
2025-03-19 17:51 ` [PATCH v2 2/3] ASoC: ops: Remove some unnecessary local variables Charles Keepax
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Charles Keepax @ 2025-03-19 17:51 UTC (permalink / raw)
To: broonie; +Cc: lgirdwood, linux-sound, linux-kernel, patches
There are only two differences between snd_soc_get_volsw() and
snd_soc_get_volsw_sx(). The maximum field is handled differently, and
snd_soc_get_volsw() supports double controls with both values in the
same register.
Factor out the common code into a new helper and pass in the
appropriate max value such that it is handled correctly for each
control.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
Changes since v1:
- Drop reg and reg2 local variables that were unused
sound/soc/soc-ops.c | 68 +++++++++++++++++++--------------------------
1 file changed, 29 insertions(+), 39 deletions(-)
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 0b62ffb2e222f..1d7c28993a631 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -243,6 +243,33 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
return ret;
}
+static int soc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc, int mask, int max)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int reg_val;
+ int val;
+
+ reg_val = snd_soc_component_read(component, mc->reg);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
+
+ ucontrol->value.integer.value[0] = val;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (mc->reg == mc->rreg) {
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
+ } else {
+ reg_val = snd_soc_component_read(component, mc->rreg);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
+ }
+
+ ucontrol->value.integer.value[1] = val;
+ }
+
+ return 0;
+}
+
/**
* snd_soc_info_volsw - single mixer info callback with range.
* @kcontrol: mixer control
@@ -299,31 +326,11 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_sx);
int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max - mc->min;
unsigned int mask = soc_mixer_mask(mc);
- unsigned int reg_val;
- int val;
- reg_val = snd_soc_component_read(component, mc->reg);
- val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
-
- ucontrol->value.integer.value[0] = val;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- if (mc->reg == mc->rreg) {
- val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
- } else {
- reg_val = snd_soc_component_read(component, mc->rreg);
- val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
- }
-
- ucontrol->value.integer.value[1] = val;
- }
-
- return 0;
+ return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min);
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
@@ -361,28 +368,11 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
unsigned int mask = soc_mixer_sx_mask(mc);
- unsigned int reg_val;
- int val;
-
- reg_val = snd_soc_component_read(component, reg);
- val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, mc->max);
-
- ucontrol->value.integer.value[0] = val;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- reg_val = snd_soc_component_read(component, reg2);
- val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, mc->max);
- ucontrol->value.integer.value[1] = val;
- }
-
- return 0;
+ return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max);
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 2/3] ASoC: ops: Remove some unnecessary local variables
2025-03-19 17:51 [PATCH v2 0/3] Tidy up ASoC control get and put handlers Charles Keepax
2025-03-19 17:51 ` [PATCH v2 1/3] ASoC: ops: Factor out common code from get callbacks Charles Keepax
@ 2025-03-19 17:51 ` Charles Keepax
2025-03-19 17:51 ` [PATCH v2 3/3] ASoC: ops: Apply platform_max after deciding control type Charles Keepax
2025-03-20 18:45 ` [PATCH v2 0/3] Tidy up ASoC control get and put handlers Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Charles Keepax @ 2025-03-19 17:51 UTC (permalink / raw)
To: broonie; +Cc: lgirdwood, linux-sound, linux-kernel, patches
Remove some local variables that aren't adding much in terms of clarity
or space saving.
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
Changes since v1:
- A couple of local variables now dropped in proceeding patch rather
than this one.
sound/soc/soc-ops.c | 42 +++++++++++++++++-------------------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 1d7c28993a631..3ac5b3a62c812 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -664,9 +664,6 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
unsigned int regwmask = GENMASK(regwshift - 1, 0);
unsigned long mask = GENMASK(mc->nbits - 1, 0);
- unsigned int invert = mc->invert;
- long min = mc->min;
- long max = mc->max;
long val = 0;
unsigned int i;
@@ -676,10 +673,10 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
val |= (regval & regwmask) << (regwshift * (regcount - i - 1));
}
val &= mask;
- if (min < 0 && val > max)
+ if (mc->min < 0 && val > mc->max)
val |= ~mask;
- if (invert)
- val = max - val;
+ if (mc->invert)
+ val = mc->max - val;
ucontrol->value.integer.value[0] = val;
return 0;
@@ -711,16 +708,14 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
unsigned int regwmask = GENMASK(regwshift - 1, 0);
unsigned long mask = GENMASK(mc->nbits - 1, 0);
- unsigned int invert = mc->invert;
- long max = mc->max;
long val = ucontrol->value.integer.value[0];
int ret = 0;
unsigned int i;
if (val < mc->min || val > mc->max)
return -EINVAL;
- if (invert)
- val = max - val;
+ if (mc->invert)
+ val = mc->max - val;
val &= mask;
for (i = 0; i < regcount; i++) {
unsigned int regval = (val >> (regwshift * (regcount - i - 1))) &
@@ -755,17 +750,16 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = BIT(shift);
unsigned int invert = mc->invert != 0;
+ unsigned int mask = BIT(mc->shift);
unsigned int val;
- val = snd_soc_component_read(component, reg);
+ val = snd_soc_component_read(component, mc->reg);
val &= mask;
- if (shift != 0 && val != 0)
- val = val >> shift;
+ if (mc->shift != 0 && val != 0)
+ val = val >> mc->shift;
+
ucontrol->value.enumerated.item[0] = val ^ invert;
return 0;
@@ -788,19 +782,17 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = BIT(shift);
- unsigned int invert = mc->invert != 0;
unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+ unsigned int invert = mc->invert != 0;
+ unsigned int mask = BIT(mc->shift);
unsigned int val1 = (strobe ^ invert) ? mask : 0;
unsigned int val2 = (strobe ^ invert) ? 0 : mask;
- int err;
+ int ret;
- err = snd_soc_component_update_bits(component, reg, mask, val1);
- if (err < 0)
- return err;
+ ret = snd_soc_component_update_bits(component, mc->reg, mask, val1);
+ if (ret < 0)
+ return ret;
- return snd_soc_component_update_bits(component, reg, mask, val2);
+ return snd_soc_component_update_bits(component, mc->reg, mask, val2);
}
EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 3/3] ASoC: ops: Apply platform_max after deciding control type
2025-03-19 17:51 [PATCH v2 0/3] Tidy up ASoC control get and put handlers Charles Keepax
2025-03-19 17:51 ` [PATCH v2 1/3] ASoC: ops: Factor out common code from get callbacks Charles Keepax
2025-03-19 17:51 ` [PATCH v2 2/3] ASoC: ops: Remove some unnecessary local variables Charles Keepax
@ 2025-03-19 17:51 ` Charles Keepax
2025-03-20 18:45 ` [PATCH v2 0/3] Tidy up ASoC control get and put handlers Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Charles Keepax @ 2025-03-19 17:51 UTC (permalink / raw)
To: broonie; +Cc: lgirdwood, linux-sound, linux-kernel, patches
It doesn't really make sense for the type of a control to change based
on the platform_max field. platform_max allows a specific system to
limit values of a control for safety but it seems reasonable the
control type should remain the same between different systems, even
if it is restricted down to just two values. Move the application of
platform_max to after control type determination in soc_info_volsw().
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
No change since v1.
sound/soc/soc-ops.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 3ac5b3a62c812..8d4dd11c9aef1 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -172,9 +172,6 @@ static int soc_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo,
struct soc_mixer_control *mc, int max)
{
- if (mc->platform_max && mc->platform_max < max)
- max = mc->platform_max;
-
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
if (max == 1) {
@@ -185,6 +182,9 @@ static int soc_info_volsw(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
}
+ if (mc->platform_max && mc->platform_max < max)
+ max = mc->platform_max;
+
uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = max;
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v2 0/3] Tidy up ASoC control get and put handlers
2025-03-19 17:51 [PATCH v2 0/3] Tidy up ASoC control get and put handlers Charles Keepax
` (2 preceding siblings ...)
2025-03-19 17:51 ` [PATCH v2 3/3] ASoC: ops: Apply platform_max after deciding control type Charles Keepax
@ 2025-03-20 18:45 ` Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2025-03-20 18:45 UTC (permalink / raw)
To: Charles Keepax; +Cc: lgirdwood, linux-sound, linux-kernel, patches
On Wed, 19 Mar 2025 17:51:20 +0000, Charles Keepax wrote:
> There is a lot of duplicated and occasionally slightly incorrect code
> around the ASoC control get and put handlers. This series add some kunit
> tests and then refactors the code to get all the tests passing and
> reduce some of the duplication. The focus here is on the volsw handlers,
> future work could still be done on some of the others but these were the
> ones that most required attention.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/3] ASoC: ops: Factor out common code from get callbacks
commit: 1e3cd64a29baa874b89180ac0744178ecb00f3cd
[2/3] ASoC: ops: Remove some unnecessary local variables
commit: 94dfe71f0a4eb0d7df542560c22961dedf45141d
[3/3] ASoC: ops: Apply platform_max after deciding control type
commit: 502a668fad12b6ca10bcbb615d62e61d3b669c99
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] 5+ messages in thread