Skip to content

Commit 05dee72

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 5bce610 commit 05dee72

3 files changed

Lines changed: 60 additions & 32 deletions

File tree

include/sound/soc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@ struct soc_mixer_control {
12251225
unsigned int sign_bit;
12261226
unsigned int invert:1;
12271227
unsigned int autodisable:1;
1228+
unsigned int sdca_q78:1;
12281229
#ifdef CONFIG_SND_SOC_TOPOLOGY
12291230
struct snd_soc_dobj dobj;
12301231
#endif

sound/soc/sdca/sdca_asoc.c

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,6 @@ static int control_limit_kctl(struct device *dev,
795795
struct sdca_control_range *range;
796796
int min, max, step;
797797
unsigned int *tlv;
798-
int shift;
799798

800799
if (control->type != SDCA_CTL_DATATYPE_Q7P8DB)
801800
return 0;
@@ -814,37 +813,22 @@ static int control_limit_kctl(struct device *dev,
814813
min = sign_extend32(min, control->nbits - 1);
815814
max = sign_extend32(max, control->nbits - 1);
816815

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-
834816
tlv = devm_kcalloc(dev, 4, sizeof(*tlv), GFP_KERNEL);
835817
if (!tlv)
836818
return -ENOMEM;
837819

838-
tlv[0] = SNDRV_CTL_TLVT_DB_SCALE;
820+
tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
839821
tlv[1] = 2 * sizeof(*tlv);
840822
tlv[2] = (min * 100) >> 8;
841-
tlv[3] = ((1 << shift) * 100) >> 8;
823+
tlv[3] = (max * 100) >> 8;
824+
825+
step = (step * 100) >> 8;
842826

843-
mc->min = min >> shift;
844-
mc->max = max >> shift;
845-
mc->shift = shift;
846-
mc->rshift = shift;
847-
mc->sign_bit = 15 - shift;
827+
mc->min = ((int)tlv[2] / step);
828+
mc->max = ((int)tlv[3] / step);
829+
mc->shift = step;
830+
mc->sign_bit = 15;
831+
mc->sdca_q78 = 1;
848832

849833
kctl->tlv.p = tlv;
850834
kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;

sound/soc/soc-ops.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,35 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
110110
}
111111
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
112112

113+
static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
114+
unsigned int mask, unsigned int shift, int max)
115+
{
116+
int val = reg_val;
117+
118+
if (WARN_ON(!mc->shift))
119+
return -EINVAL;
120+
121+
val = sign_extend32(val, mc->sign_bit);
122+
val = (((val * 100) >> 8) / (int)mc->shift);
123+
val -= mc->min;
124+
125+
return val & mask;
126+
}
127+
128+
static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
129+
unsigned int mask, unsigned int shift, int max)
130+
{
131+
unsigned int reg_val, ret_val;
132+
133+
if (WARN_ON(!mc->shift))
134+
return -EINVAL;
135+
136+
reg_val = val + mc->min;
137+
ret_val = (((int)(((int)reg_val * (int)mc->shift) << 8)) / 100);
138+
139+
return ret_val & mask;
140+
}
141+
113142
static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
114143
unsigned int mask, unsigned int shift, int max)
115144
{
@@ -202,27 +231,35 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
202231
unsigned int val2 = 0;
203232
bool double_r = false;
204233
int ret;
234+
unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
235+
236+
if (mc->sdca_q78) {
237+
ctl_to_reg = sdca_soc_q78_ctl_to_reg;
238+
val_mask = mask;
239+
} else {
240+
ctl_to_reg = soc_mixer_ctl_to_reg;
241+
val_mask = mask << mc->shift;
242+
}
205243

206244
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
207245
if (ret)
208246
return ret;
209247

210-
val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0],
248+
val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0],
211249
mask, mc->shift, max);
212-
val_mask = mask << mc->shift;
213250

214251
if (snd_soc_volsw_is_stereo(mc)) {
215252
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max);
216253
if (ret)
217254
return ret;
218255

219256
if (mc->reg == mc->rreg) {
220-
val1 |= soc_mixer_ctl_to_reg(mc,
257+
val1 |= ctl_to_reg(mc,
221258
ucontrol->value.integer.value[1],
222259
mask, mc->rshift, max);
223260
val_mask |= mask << mc->rshift;
224261
} else {
225-
val2 = soc_mixer_ctl_to_reg(mc,
262+
val2 = ctl_to_reg(mc,
226263
ucontrol->value.integer.value[1],
227264
mask, mc->shift, max);
228265
double_r = true;
@@ -251,18 +288,24 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol,
251288
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
252289
unsigned int reg_val;
253290
int val;
291+
int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int);
292+
293+
if (mc->sdca_q78)
294+
reg_to_ctl = sdca_soc_q78_reg_to_ctl;
295+
else
296+
reg_to_ctl = soc_mixer_reg_to_ctl;
254297

255298
reg_val = snd_soc_component_read(component, mc->reg);
256-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
299+
val = reg_to_ctl(mc, reg_val, mask, mc->shift, max);
257300

258301
ucontrol->value.integer.value[0] = val;
259302

260303
if (snd_soc_volsw_is_stereo(mc)) {
261304
if (mc->reg == mc->rreg) {
262-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
305+
val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
263306
} else {
264307
reg_val = snd_soc_component_read(component, mc->rreg);
265-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
308+
val = reg_to_ctl(mc, reg_val, mask, mc->shift, max);
266309
}
267310

268311
ucontrol->value.integer.value[1] = val;

0 commit comments

Comments
 (0)