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: SOF: ipc4-control: Support for Switch and Enum

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

Currently IPC4 has no notion of a switch or enum type of control which
is a generic concept in ALSA.

The generic support for these control types will be as follows:

- large config is used to send the channel-value par array
- param_id of a SWITCH type is 200
- param_id of an ENUM type is 201

Each module need to support a switch or/and enum must handle these
universal param_ids. The message payload is described by struct
sof_ipc4_control_msg_payload.

+237 -6
+173 -2
sound/soc/sof/ipc4-control.c
··· 201 201 return 0; 202 202 } 203 203 204 + static int 205 + sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev, 206 + struct snd_sof_widget *swidget, 207 + struct snd_sof_control *scontrol, bool lock) 208 + { 209 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 210 + struct sof_ipc4_control_msg_payload *data; 211 + struct sof_ipc4_msg *msg = &cdata->msg; 212 + size_t data_size; 213 + unsigned int i; 214 + int ret; 215 + 216 + data_size = struct_size(data, chanv, scontrol->num_channels); 217 + data = kzalloc(data_size, GFP_KERNEL); 218 + if (!data) 219 + return -ENOMEM; 220 + 221 + data->id = cdata->index; 222 + data->num_elems = scontrol->num_channels; 223 + for (i = 0; i < scontrol->num_channels; i++) { 224 + data->chanv[i].channel = cdata->chanv[i].channel; 225 + data->chanv[i].value = cdata->chanv[i].value; 226 + } 227 + 228 + msg->data_ptr = data; 229 + msg->data_size = data_size; 230 + 231 + ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock); 232 + msg->data_ptr = NULL; 233 + msg->data_size = 0; 234 + if (ret < 0) 235 + dev_err(sdev->dev, "Failed to set control update for %s\n", 236 + scontrol->name); 237 + 238 + kfree(data); 239 + 240 + return ret; 241 + } 242 + 243 + static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, 244 + struct snd_ctl_elem_value *ucontrol) 245 + { 246 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 247 + struct snd_soc_component *scomp = scontrol->scomp; 248 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 249 + struct snd_sof_widget *swidget; 250 + bool widget_found = false; 251 + bool change = false; 252 + unsigned int i; 253 + u32 value; 254 + int ret; 255 + 256 + /* update each channel */ 257 + for (i = 0; i < scontrol->num_channels; i++) { 258 + value = ucontrol->value.integer.value[i]; 259 + change = change || (value != cdata->chanv[i].value); 260 + cdata->chanv[i].channel = i; 261 + cdata->chanv[i].value = value; 262 + } 263 + 264 + if (!pm_runtime_active(scomp->dev)) 265 + return change; 266 + 267 + /* find widget associated with the control */ 268 + list_for_each_entry(swidget, &sdev->widget_list, list) { 269 + if (swidget->comp_id == scontrol->comp_id) { 270 + widget_found = true; 271 + break; 272 + } 273 + } 274 + 275 + if (!widget_found) { 276 + dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); 277 + return false; 278 + } 279 + 280 + ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true); 281 + if (ret < 0) 282 + return false; 283 + 284 + return change; 285 + } 286 + 287 + static int sof_ipc4_switch_get(struct snd_sof_control *scontrol, 288 + struct snd_ctl_elem_value *ucontrol) 289 + { 290 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 291 + unsigned int i; 292 + 293 + /* read back each channel */ 294 + for (i = 0; i < scontrol->num_channels; i++) 295 + ucontrol->value.integer.value[i] = cdata->chanv[i].value; 296 + 297 + return 0; 298 + } 299 + 300 + static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol, 301 + struct snd_ctl_elem_value *ucontrol) 302 + { 303 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 304 + struct snd_soc_component *scomp = scontrol->scomp; 305 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 306 + struct snd_sof_widget *swidget; 307 + bool widget_found = false; 308 + bool change = false; 309 + unsigned int i; 310 + u32 value; 311 + int ret; 312 + 313 + /* update each channel */ 314 + for (i = 0; i < scontrol->num_channels; i++) { 315 + value = ucontrol->value.enumerated.item[i]; 316 + change = change || (value != cdata->chanv[i].value); 317 + cdata->chanv[i].channel = i; 318 + cdata->chanv[i].value = value; 319 + } 320 + 321 + if (!pm_runtime_active(scomp->dev)) 322 + return change; 323 + 324 + /* find widget associated with the control */ 325 + list_for_each_entry(swidget, &sdev->widget_list, list) { 326 + if (swidget->comp_id == scontrol->comp_id) { 327 + widget_found = true; 328 + break; 329 + } 330 + } 331 + 332 + if (!widget_found) { 333 + dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); 334 + return false; 335 + } 336 + 337 + ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true); 338 + if (ret < 0) 339 + return false; 340 + 341 + return change; 342 + } 343 + 344 + static int sof_ipc4_enum_get(struct snd_sof_control *scontrol, 345 + struct snd_ctl_elem_value *ucontrol) 346 + { 347 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 348 + unsigned int i; 349 + 350 + /* read back each channel */ 351 + for (i = 0; i < scontrol->num_channels; i++) 352 + ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; 353 + 354 + return 0; 355 + } 356 + 204 357 static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev, 205 358 struct snd_sof_control *scontrol, 206 359 bool set, bool lock) ··· 591 438 return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true); 592 439 } 593 440 441 + static int 442 + sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 443 + struct snd_sof_control *scontrol) 444 + { 445 + if (scontrol->max == 1) 446 + return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false); 447 + 448 + return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false); 449 + } 450 + 594 451 /* set up all controls for the widget */ 595 452 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 596 453 { ··· 613 450 case SND_SOC_TPLG_CTL_VOLSW: 614 451 case SND_SOC_TPLG_CTL_VOLSW_SX: 615 452 case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 616 - ret = sof_ipc4_set_volume_data(sdev, swidget, 617 - scontrol, false); 453 + ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol); 618 454 break; 619 455 case SND_SOC_TPLG_CTL_BYTES: 620 456 ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, 621 457 true, false); 458 + break; 459 + case SND_SOC_TPLG_CTL_ENUM: 460 + case SND_SOC_TPLG_CTL_ENUM_VALUE: 461 + ret = sof_ipc4_set_generic_control_data(sdev, swidget, 462 + scontrol, false); 622 463 break; 623 464 default: 624 465 break; ··· 665 498 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = { 666 499 .volume_put = sof_ipc4_volume_put, 667 500 .volume_get = sof_ipc4_volume_get, 501 + .switch_put = sof_ipc4_switch_put, 502 + .switch_get = sof_ipc4_switch_get, 503 + .enum_put = sof_ipc4_enum_put, 504 + .enum_get = sof_ipc4_enum_get, 668 505 .bytes_put = sof_ipc4_bytes_put, 669 506 .bytes_get = sof_ipc4_bytes_get, 670 507 .bytes_ext_put = sof_ipc4_bytes_ext_put,
+46 -3
sound/soc/sof/ipc4-topology.c
··· 2107 2107 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2108 2108 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2109 2109 2110 - msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 2110 + /* volume controls with range 0-1 (off/on) are switch controls */ 2111 + if (scontrol->max == 1) 2112 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID); 2113 + else 2114 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 2111 2115 2112 - /* set default volume values to 0dB in control */ 2113 2116 for (i = 0; i < scontrol->num_channels; i++) { 2114 2117 control_data->chanv[i].channel = i; 2115 - control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 2118 + /* 2119 + * Default, initial values: 2120 + * - 0dB for volume controls 2121 + * - off (0) for switch controls - value already zero after 2122 + * memory allocation 2123 + */ 2124 + if (scontrol->max > 1) 2125 + control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 2116 2126 } 2127 + 2128 + return 0; 2129 + } 2130 + 2131 + static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 2132 + { 2133 + struct sof_ipc4_control_data *control_data; 2134 + struct sof_ipc4_msg *msg; 2135 + int i; 2136 + 2137 + scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 2138 + 2139 + /* scontrol->ipc_control_data will be freed in sof_control_unload */ 2140 + scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 2141 + if (!scontrol->ipc_control_data) 2142 + return -ENOMEM; 2143 + 2144 + control_data = scontrol->ipc_control_data; 2145 + control_data->index = scontrol->index; 2146 + 2147 + msg = &control_data->msg; 2148 + msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 2149 + msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2150 + msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2151 + 2152 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID); 2153 + 2154 + /* Default, initial value for enums: first enum entry is selected (0) */ 2155 + for (i = 0; i < scontrol->num_channels; i++) 2156 + control_data->chanv[i].channel = i; 2117 2157 2118 2158 return 0; 2119 2159 } ··· 2232 2192 return sof_ipc4_control_load_volume(sdev, scontrol); 2233 2193 case SND_SOC_TPLG_CTL_BYTES: 2234 2194 return sof_ipc4_control_load_bytes(sdev, scontrol); 2195 + case SND_SOC_TPLG_CTL_ENUM: 2196 + case SND_SOC_TPLG_CTL_ENUM_VALUE: 2197 + return sof_ipc4_control_load_enum(sdev, scontrol); 2235 2198 default: 2236 2199 break; 2237 2200 }
+18 -1
sound/soc/sof/ipc4-topology.h
··· 319 319 /** 320 320 * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data 321 321 * @channel: Channel ID 322 - * @value: gain value 322 + * @value: Value associated with @channel 323 323 */ 324 324 struct sof_ipc4_ctrl_value_chan { 325 325 u32 channel; ··· 342 342 DECLARE_FLEX_ARRAY(struct sof_abi_hdr, data); 343 343 }; 344 344 }; 345 + 346 + #define SOF_IPC4_SWITCH_CONTROL_PARAM_ID 200 347 + #define SOF_IPC4_ENUM_CONTROL_PARAM_ID 201 348 + 349 + /** 350 + * struct sof_ipc4_control_msg_payload - IPC payload for kcontrol parameters 351 + * @id: unique id of the control 352 + * @num_elems: Number of elements in the chanv array 353 + * @reserved: reserved for future use, must be set to 0 354 + * @chanv: channel ID and value array 355 + */ 356 + struct sof_ipc4_control_msg_payload { 357 + uint16_t id; 358 + uint16_t num_elems; 359 + uint32_t reserved[4]; 360 + DECLARE_FLEX_ARRAY(struct sof_ipc4_ctrl_value_chan, chanv); 361 + } __packed; 345 362 346 363 /** 347 364 * struct sof_ipc4_gain_data - IPC gain blob