Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20251106093335.1363237-1-shumingf@realtek.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Shuming Fan and committed by
Mark Brown
1b0f3f9e 6d34b66f

+61 -36
+1
include/sound/soc.h
··· 1225 1225 unsigned int sign_bit; 1226 1226 unsigned int invert:1; 1227 1227 unsigned int autodisable:1; 1228 + unsigned int sdca_q78:1; 1228 1229 #ifdef CONFIG_SND_SOC_TOPOLOGY 1229 1230 struct snd_soc_dobj dobj; 1230 1231 #endif
+9 -25
sound/soc/sdca/sdca_asoc.c
··· 795 795 struct sdca_control_range *range; 796 796 int min, max, step; 797 797 unsigned int *tlv; 798 - int shift; 799 798 800 799 if (control->type != SDCA_CTL_DATATYPE_Q7P8DB) 801 800 return 0; ··· 813 814 min = sign_extend32(min, control->nbits - 1); 814 815 max = sign_extend32(max, control->nbits - 1); 815 816 816 - /* 817 - * FIXME: Only support power of 2 step sizes as this can be supported 818 - * by a simple shift. 819 - */ 820 - if (hweight32(step) != 1) { 821 - dev_err(dev, "%s: %s: currently unsupported step size\n", 822 - entity->label, control->label); 823 - return -EINVAL; 824 - } 825 - 826 - /* 827 - * The SDCA volumes are in steps of 1/256th of a dB, a step down of 828 - * 64 (shift of 6) gives 1/4dB. 1/4dB is the smallest unit that is also 829 - * representable in the ALSA TLVs which are in 1/100ths of a dB. 830 - */ 831 - shift = max(ffs(step) - 1, 6); 832 - 833 817 tlv = devm_kcalloc(dev, 4, sizeof(*tlv), GFP_KERNEL); 834 818 if (!tlv) 835 819 return -ENOMEM; 836 820 837 - tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; 821 + tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; 838 822 tlv[1] = 2 * sizeof(*tlv); 839 823 tlv[2] = (min * 100) >> 8; 840 - tlv[3] = ((1 << shift) * 100) >> 8; 824 + tlv[3] = (max * 100) >> 8; 841 825 842 - mc->min = min >> shift; 843 - mc->max = max >> shift; 844 - mc->shift = shift; 845 - mc->rshift = shift; 846 - mc->sign_bit = 15 - shift; 826 + step = (step * 100) >> 8; 827 + 828 + mc->min = ((int)tlv[2] / step); 829 + mc->max = ((int)tlv[3] / step); 830 + mc->shift = step; 831 + mc->sign_bit = 15; 832 + mc->sdca_q78 = 1; 847 833 848 834 kctl->tlv.p = tlv; 849 835 kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+51 -11
sound/soc/soc-ops.c
··· 110 110 } 111 111 EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); 112 112 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 + 113 143 static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, 114 144 unsigned int mask, unsigned int shift, int max) 115 145 { ··· 227 197 struct snd_ctl_elem_value *ucontrol, 228 198 struct soc_mixer_control *mc, int mask, int max) 229 199 { 200 + unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int); 230 201 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 231 202 unsigned int val1, val_mask; 232 203 unsigned int val2 = 0; 233 204 bool double_r = false; 234 205 int ret; 235 206 207 + if (mc->sdca_q78) { 208 + ctl_to_reg = sdca_soc_q78_ctl_to_reg; 209 + val_mask = mask; 210 + } else { 211 + ctl_to_reg = soc_mixer_ctl_to_reg; 212 + val_mask = mask << mc->shift; 213 + } 214 + 236 215 ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max); 237 216 if (ret) 238 217 return ret; 239 218 240 - val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0], 219 + val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0], 241 220 mask, mc->shift, max); 242 - val_mask = mask << mc->shift; 243 221 244 222 if (snd_soc_volsw_is_stereo(mc)) { 245 223 ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max); ··· 255 217 return ret; 256 218 257 219 if (mc->reg == mc->rreg) { 258 - val1 |= soc_mixer_ctl_to_reg(mc, 259 - ucontrol->value.integer.value[1], 260 - mask, mc->rshift, max); 220 + val1 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max); 261 221 val_mask |= mask << mc->rshift; 262 222 } else { 263 - val2 = soc_mixer_ctl_to_reg(mc, 264 - ucontrol->value.integer.value[1], 265 - mask, mc->shift, max); 223 + val2 = ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->shift, max); 266 224 double_r = true; 267 225 } 268 226 } ··· 282 248 struct snd_ctl_elem_value *ucontrol, 283 249 struct soc_mixer_control *mc, int mask, int max) 284 250 { 251 + int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int); 285 252 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 286 253 unsigned int reg_val; 287 254 int val; 288 255 256 + if (mc->sdca_q78) 257 + reg_to_ctl = sdca_soc_q78_reg_to_ctl; 258 + else 259 + reg_to_ctl = soc_mixer_reg_to_ctl; 260 + 289 261 reg_val = snd_soc_component_read(component, mc->reg); 290 - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); 262 + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); 291 263 292 264 ucontrol->value.integer.value[0] = val; 293 265 294 266 if (snd_soc_volsw_is_stereo(mc)) { 295 267 if (mc->reg == mc->rreg) { 296 - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max); 268 + val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max); 297 269 } else { 298 270 reg_val = snd_soc_component_read(component, mc->rreg); 299 - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); 271 + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); 300 272 } 301 273 302 274 ucontrol->value.integer.value[1] = val;