Skip to content

Commit 27731dd

Browse files
committed
ASoC: SDCA: support Q7.8 volume format
The SDCA specification uses Q7.8 volume format. This patch adds a field to indicate whether it is SDCA volume control and supports the volume settings. Signed-off-by: Shuming Fan <shumingf@realtek.com>
1 parent 951dec3 commit 27731dd

2 files changed

Lines changed: 133 additions & 25 deletions

File tree

include/sound/soc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ struct soc_mixer_control {
12201220
/* Limited maximum value specified as presented through the control */
12211221
int platform_max;
12221222
int reg, rreg;
1223+
int step;
12231224
unsigned int shift, rshift;
12241225
u32 num_channels;
12251226
unsigned int sign_bit;

sound/soc/sdca/sdca_asoc.c

Lines changed: 132 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,126 @@ int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *funct
786786
}
787787
EXPORT_SYMBOL_NS(sdca_asoc_populate_dapm, "SND_SOC_SDCA");
788788

789+
static int sdca_soc_vol_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
790+
unsigned int mask, int max)
791+
{
792+
int val = reg_val;
793+
794+
if (WARN_ON(!mc->step))
795+
return -EINVAL;
796+
797+
if (mc->sign_bit)
798+
val = sign_extend32(val, mc->sign_bit);
799+
800+
val = (((val * 100) >> 8) / mc->step);
801+
802+
val -= mc->min;
803+
804+
if (mc->invert)
805+
val = max - val;
806+
807+
return val & mask;
808+
}
809+
810+
static unsigned int sdca_soc_vol_ctl_to_reg(struct soc_mixer_control *mc, int val,
811+
unsigned int mask, int max)
812+
{
813+
unsigned int reg_val, ret_val;
814+
815+
if (WARN_ON(!mc->step))
816+
return -EINVAL;
817+
818+
if (mc->invert)
819+
val = max - val;
820+
821+
reg_val = val + mc->min;
822+
823+
ret_val = (((int)(((int)reg_val * mc->step) << 8)) / 100);
824+
825+
return ret_val & mask;
826+
}
827+
828+
static int sdca_soc_put_volsw(struct snd_kcontrol *kcontrol,
829+
struct snd_ctl_elem_value *ucontrol)
830+
{
831+
struct soc_mixer_control *mc =
832+
(struct soc_mixer_control *)kcontrol->private_value;
833+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
834+
int max = mc->max - mc->min;
835+
unsigned int val1, val2;
836+
bool double_r = false;
837+
unsigned int mask;
838+
int ret;
839+
840+
if (mc->sign_bit)
841+
mask = GENMASK(mc->sign_bit, 0);
842+
else
843+
mask = GENMASK(fls(mc->max) - 1, 0);
844+
845+
val1 = sdca_soc_vol_ctl_to_reg(mc, ucontrol->value.integer.value[0], mask, max);
846+
847+
if (snd_soc_volsw_is_stereo(mc)) {
848+
if (mc->reg == mc->rreg) {
849+
val1 |= sdca_soc_vol_ctl_to_reg(mc,
850+
ucontrol->value.integer.value[1],
851+
mask, max);
852+
} else {
853+
val2 = sdca_soc_vol_ctl_to_reg(mc,
854+
ucontrol->value.integer.value[1],
855+
mask, max);
856+
double_r = true;
857+
}
858+
}
859+
860+
ret = snd_soc_component_update_bits(component, mc->reg, mask, val1);
861+
if (ret < 0)
862+
return ret;
863+
864+
if (double_r) {
865+
int err = snd_soc_component_update_bits(component, mc->rreg,
866+
mask, val2);
867+
if (err)
868+
return err;
869+
}
870+
871+
return ret;
872+
}
873+
874+
static int sdca_soc_get_volsw(struct snd_kcontrol *kcontrol,
875+
struct snd_ctl_elem_value *ucontrol)
876+
{
877+
struct soc_mixer_control *mc =
878+
(struct soc_mixer_control *)kcontrol->private_value;
879+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
880+
int max = mc->max - mc->min;
881+
unsigned int reg_val;
882+
unsigned int mask;
883+
int val;
884+
885+
if (mc->sign_bit)
886+
mask = GENMASK(mc->sign_bit, 0);
887+
else
888+
mask = GENMASK(fls(mc->max) - 1, 0);
889+
890+
reg_val = snd_soc_component_read(component, mc->reg);
891+
val = sdca_soc_vol_reg_to_ctl(mc, reg_val, mask, max);
892+
893+
ucontrol->value.integer.value[0] = val;
894+
895+
if (snd_soc_volsw_is_stereo(mc)) {
896+
if (mc->reg == mc->rreg) {
897+
val = sdca_soc_vol_reg_to_ctl(mc, reg_val, mask, max);
898+
} else {
899+
reg_val = snd_soc_component_read(component, mc->rreg);
900+
val = sdca_soc_vol_reg_to_ctl(mc, reg_val, mask, max);
901+
}
902+
903+
ucontrol->value.integer.value[1] = val;
904+
}
905+
906+
return 0;
907+
}
908+
789909
static int control_limit_kctl(struct device *dev,
790910
struct sdca_entity *entity,
791911
struct sdca_control *control,
@@ -795,7 +915,6 @@ static int control_limit_kctl(struct device *dev,
795915
struct sdca_control_range *range;
796916
int min, max, step;
797917
unsigned int *tlv;
798-
int shift;
799918

800919
if (control->type != SDCA_CTL_DATATYPE_Q7P8DB)
801920
return 0;
@@ -814,41 +933,29 @@ static int control_limit_kctl(struct device *dev,
814933
min = sign_extend32(min, control->nbits - 1);
815934
max = sign_extend32(max, control->nbits - 1);
816935

817-
/*
818-
* FIXME: Only support power of 2 step sizes as this can be supported
819-
* by a simple shift.
820-
*/
821-
if (hweight32(step) != 1) {
822-
dev_err(dev, "%s: %s: currently unsupported step size\n",
823-
entity->label, control->label);
824-
return -EINVAL;
825-
}
826-
827-
/*
828-
* The SDCA volumes are in steps of 1/256th of a dB, a step down of
829-
* 64 (shift of 6) gives 1/4dB. 1/4dB is the smallest unit that is also
830-
* representable in the ALSA TLVs which are in 1/100ths of a dB.
831-
*/
832-
shift = max(ffs(step) - 1, 6);
833-
834936
tlv = devm_kcalloc(dev, 4, sizeof(*tlv), GFP_KERNEL);
835937
if (!tlv)
836938
return -ENOMEM;
837939

838-
tlv[0] = SNDRV_CTL_TLVT_DB_SCALE;
940+
tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
839941
tlv[1] = 2 * sizeof(*tlv);
840942
tlv[2] = (min * 100) >> 8;
841-
tlv[3] = ((1 << shift) * 100) >> 8;
943+
tlv[3] = (max * 100) >> 8;
944+
945+
step = (step * 100) >> 8;
842946

843-
mc->min = min >> shift;
844-
mc->max = max >> shift;
845-
mc->shift = shift;
846-
mc->rshift = shift;
847-
mc->sign_bit = 15 - shift;
947+
mc->min = ((int)tlv[2] / step);
948+
mc->max = ((int)tlv[3] / step);
949+
mc->shift = mc->rshift = 0;
950+
mc->sign_bit = 15;
951+
mc->step = step;
848952

849953
kctl->tlv.p = tlv;
850954
kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
851955

956+
kctl->get = sdca_soc_get_volsw;
957+
kctl->put = sdca_soc_put_volsw;
958+
852959
return 0;
853960
}
854961

0 commit comments

Comments
 (0)