Skip to content

Commit c65c386

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 402ed86 commit c65c386

3 files changed

Lines changed: 61 additions & 36 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: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,36 @@ 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 ret_val;
132+
int reg_val;
133+
134+
if (WARN_ON(!mc->shift))
135+
return -EINVAL;
136+
137+
reg_val = val + mc->min;
138+
ret_val = (int)((reg_val * mc->shift) << 8) / 100;
139+
140+
return ret_val & mask;
141+
}
142+
113143
static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
114144
unsigned int mask, unsigned int shift, int max)
115145
{
@@ -202,29 +232,33 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
202232
unsigned int val2 = 0;
203233
bool double_r = false;
204234
int ret;
235+
unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
236+
237+
if (mc->sdca_q78) {
238+
ctl_to_reg = sdca_soc_q78_ctl_to_reg;
239+
val_mask = mask;
240+
} else {
241+
ctl_to_reg = soc_mixer_ctl_to_reg;
242+
val_mask = mask << mc->shift;
243+
}
205244

206245
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
207246
if (ret)
208247
return ret;
209248

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

214252
if (snd_soc_volsw_is_stereo(mc)) {
215253
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max);
216254
if (ret)
217255
return ret;
218256

219257
if (mc->reg == mc->rreg) {
220-
val1 |= soc_mixer_ctl_to_reg(mc,
221-
ucontrol->value.integer.value[1],
222-
mask, mc->rshift, max);
258+
val1 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max);
223259
val_mask |= mask << mc->rshift;
224260
} else {
225-
val2 = soc_mixer_ctl_to_reg(mc,
226-
ucontrol->value.integer.value[1],
227-
mask, mc->shift, max);
261+
val2 = ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->shift, max);
228262
double_r = true;
229263
}
230264
}
@@ -251,18 +285,24 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol,
251285
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
252286
unsigned int reg_val;
253287
int val;
288+
int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int);
289+
290+
if (mc->sdca_q78)
291+
reg_to_ctl = sdca_soc_q78_reg_to_ctl;
292+
else
293+
reg_to_ctl = soc_mixer_reg_to_ctl;
254294

255295
reg_val = snd_soc_component_read(component, mc->reg);
256-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
296+
val = reg_to_ctl(mc, reg_val, mask, mc->shift, max);
257297

258298
ucontrol->value.integer.value[0] = val;
259299

260300
if (snd_soc_volsw_is_stereo(mc)) {
261301
if (mc->reg == mc->rreg) {
262-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
302+
val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
263303
} else {
264304
reg_val = snd_soc_component_read(component, mc->rreg);
265-
val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
305+
val = reg_to_ctl(mc, reg_val, mask, mc->shift, max);
266306
}
267307

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

0 commit comments

Comments
 (0)