xref: /linux/sound/soc/sof/ipc3-control.c (revision 50501936288d6a29d7ef78f25d00e33240fad45f)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2021 Intel Corporation. All rights reserved.
7 //
8 //
9 
10 #include "sof-priv.h"
11 #include "sof-audio.h"
12 #include "ipc3-priv.h"
13 
14 /* IPC set()/get() for kcontrols. */
15 static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol,
16 					  bool set, bool lock)
17 {
18 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
19 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
20 	const struct sof_ipc_ops *iops = sdev->ipc->ops;
21 	enum sof_ipc_ctrl_type ctrl_type;
22 	struct snd_sof_widget *swidget;
23 	bool widget_found = false;
24 	u32 ipc_cmd, msg_bytes;
25 	int ret = 0;
26 
27 	list_for_each_entry(swidget, &sdev->widget_list, list) {
28 		if (swidget->comp_id == scontrol->comp_id) {
29 			widget_found = true;
30 			break;
31 		}
32 	}
33 
34 	if (!widget_found) {
35 		dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__,
36 			scontrol->comp_id);
37 		return -EINVAL;
38 	}
39 
40 	if (lock)
41 		mutex_lock(&swidget->setup_mutex);
42 	else
43 		lockdep_assert_held(&swidget->setup_mutex);
44 
45 	/*
46 	 * Volatile controls should always be part of static pipelines and the
47 	 * widget use_count would always be > 0 in this case. For the others,
48 	 * just return the cached value if the widget is not set up.
49 	 */
50 	if (!swidget->use_count)
51 		goto unlock;
52 
53 	/*
54 	 * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
55 	 * direction
56 	 * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
57 	 *	 for ctrl_type
58 	 */
59 	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
60 		ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
61 		ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
62 	} else {
63 		ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
64 		ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
65 	}
66 
67 	cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
68 	cdata->type = ctrl_type;
69 	cdata->comp_id = scontrol->comp_id;
70 	cdata->msg_index = 0;
71 
72 	/* calculate header and data size */
73 	switch (cdata->type) {
74 	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
75 	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
76 		cdata->num_elems = scontrol->num_channels;
77 
78 		msg_bytes = scontrol->num_channels *
79 			    sizeof(struct sof_ipc_ctrl_value_chan);
80 		msg_bytes += sizeof(struct sof_ipc_ctrl_data);
81 		break;
82 	case SOF_CTRL_TYPE_DATA_GET:
83 	case SOF_CTRL_TYPE_DATA_SET:
84 		cdata->num_elems = cdata->data->size;
85 
86 		msg_bytes = cdata->data->size;
87 		msg_bytes += sizeof(struct sof_ipc_ctrl_data) +
88 			     sizeof(struct sof_abi_hdr);
89 		break;
90 	default:
91 		ret = -EINVAL;
92 		goto unlock;
93 	}
94 
95 	cdata->rhdr.hdr.size = msg_bytes;
96 	cdata->elems_remaining = 0;
97 
98 	ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
99 
100 unlock:
101 	if (lock)
102 		mutex_unlock(&swidget->setup_mutex);
103 
104 	return ret;
105 }
106 
107 static void sof_ipc3_refresh_control(struct snd_sof_control *scontrol)
108 {
109 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
110 	struct snd_soc_component *scomp = scontrol->scomp;
111 	int ret;
112 
113 	if (!scontrol->comp_data_dirty)
114 		return;
115 
116 	if (!pm_runtime_active(scomp->dev))
117 		return;
118 
119 	/* set the ABI header values */
120 	cdata->data->magic = SOF_ABI_MAGIC;
121 	cdata->data->abi = SOF_ABI_VERSION;
122 
123 	/* refresh the component data from DSP */
124 	scontrol->comp_data_dirty = false;
125 	ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true);
126 	if (ret < 0) {
127 		dev_err(scomp->dev, "Failed to get control data: %d\n", ret);
128 
129 		/* Set the flag to re-try next time to get the data */
130 		scontrol->comp_data_dirty = true;
131 	}
132 }
133 
134 static int sof_ipc3_volume_get(struct snd_sof_control *scontrol,
135 			       struct snd_ctl_elem_value *ucontrol)
136 {
137 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
138 	unsigned int channels = scontrol->num_channels;
139 	unsigned int i;
140 
141 	sof_ipc3_refresh_control(scontrol);
142 
143 	/* read back each channel */
144 	for (i = 0; i < channels; i++)
145 		ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
146 								scontrol->volume_table,
147 								scontrol->max + 1);
148 
149 	return 0;
150 }
151 
152 static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol,
153 				struct snd_ctl_elem_value *ucontrol)
154 {
155 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
156 	struct snd_soc_component *scomp = scontrol->scomp;
157 	unsigned int channels = scontrol->num_channels;
158 	unsigned int i;
159 	bool change = false;
160 
161 	/* update each channel */
162 	for (i = 0; i < channels; i++) {
163 		u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
164 					 scontrol->volume_table, scontrol->max + 1);
165 
166 		change = change || (value != cdata->chanv[i].value);
167 		cdata->chanv[i].channel = i;
168 		cdata->chanv[i].value = value;
169 	}
170 
171 	/* notify DSP of mixer updates */
172 	if (pm_runtime_active(scomp->dev)) {
173 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
174 
175 		if (ret < 0) {
176 			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
177 				scontrol->name);
178 			return false;
179 		}
180 	}
181 
182 	return change;
183 }
184 
185 static int sof_ipc3_switch_get(struct snd_sof_control *scontrol,
186 			       struct snd_ctl_elem_value *ucontrol)
187 {
188 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
189 	unsigned int channels = scontrol->num_channels;
190 	unsigned int i;
191 
192 	sof_ipc3_refresh_control(scontrol);
193 
194 	/* read back each channel */
195 	for (i = 0; i < channels; i++)
196 		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
197 
198 	return 0;
199 }
200 
201 static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol,
202 				struct snd_ctl_elem_value *ucontrol)
203 {
204 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
205 	struct snd_soc_component *scomp = scontrol->scomp;
206 	unsigned int channels = scontrol->num_channels;
207 	unsigned int i;
208 	bool change = false;
209 	u32 value;
210 
211 	/* update each channel */
212 	for (i = 0; i < channels; i++) {
213 		value = ucontrol->value.integer.value[i];
214 		change = change || (value != cdata->chanv[i].value);
215 		cdata->chanv[i].channel = i;
216 		cdata->chanv[i].value = value;
217 	}
218 
219 	/* notify DSP of mixer updates */
220 	if (pm_runtime_active(scomp->dev)) {
221 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
222 
223 		if (ret < 0) {
224 			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
225 				scontrol->name);
226 			return false;
227 		}
228 	}
229 
230 	return change;
231 }
232 
233 static int sof_ipc3_enum_get(struct snd_sof_control *scontrol,
234 			     struct snd_ctl_elem_value *ucontrol)
235 {
236 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
237 	unsigned int channels = scontrol->num_channels;
238 	unsigned int i;
239 
240 	sof_ipc3_refresh_control(scontrol);
241 
242 	/* read back each channel */
243 	for (i = 0; i < channels; i++)
244 		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
245 
246 	return 0;
247 }
248 
249 static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol,
250 			      struct snd_ctl_elem_value *ucontrol)
251 {
252 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
253 	struct snd_soc_component *scomp = scontrol->scomp;
254 	unsigned int channels = scontrol->num_channels;
255 	unsigned int i;
256 	bool change = false;
257 	u32 value;
258 
259 	/* update each channel */
260 	for (i = 0; i < channels; i++) {
261 		value = ucontrol->value.enumerated.item[i];
262 		change = change || (value != cdata->chanv[i].value);
263 		cdata->chanv[i].channel = i;
264 		cdata->chanv[i].value = value;
265 	}
266 
267 	/* notify DSP of enum updates */
268 	if (pm_runtime_active(scomp->dev)) {
269 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
270 
271 		if (ret < 0) {
272 			dev_err(scomp->dev, "Failed to set enum updates for %s\n",
273 				scontrol->name);
274 			return false;
275 		}
276 	}
277 
278 	return change;
279 }
280 
281 static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol,
282 			      struct snd_ctl_elem_value *ucontrol)
283 {
284 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
285 	struct snd_soc_component *scomp = scontrol->scomp;
286 	struct sof_abi_hdr *data = cdata->data;
287 	size_t size;
288 
289 	sof_ipc3_refresh_control(scontrol);
290 
291 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
292 		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
293 				    scontrol->max_size);
294 		return -EINVAL;
295 	}
296 
297 	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
298 	if (data->size > scontrol->max_size - sizeof(*data)) {
299 		dev_err_ratelimited(scomp->dev,
300 				    "%u bytes of control data is invalid, max is %zu\n",
301 				    data->size, scontrol->max_size - sizeof(*data));
302 		return -EINVAL;
303 	}
304 
305 	size = data->size + sizeof(*data);
306 
307 	/* copy back to kcontrol */
308 	memcpy(ucontrol->value.bytes.data, data, size);
309 
310 	return 0;
311 }
312 
313 static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
314 			      struct snd_ctl_elem_value *ucontrol)
315 {
316 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
317 	struct snd_soc_component *scomp = scontrol->scomp;
318 	struct sof_abi_hdr *data = cdata->data;
319 	size_t size;
320 
321 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
322 		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
323 				    scontrol->max_size);
324 		return -EINVAL;
325 	}
326 
327 	/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
328 	if (data->size > scontrol->max_size - sizeof(*data)) {
329 		dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n",
330 				    data->size, scontrol->max_size - sizeof(*data));
331 		return -EINVAL;
332 	}
333 
334 	size = data->size + sizeof(*data);
335 
336 	/* copy from kcontrol */
337 	memcpy(data, ucontrol->value.bytes.data, size);
338 
339 	/* notify DSP of byte control updates */
340 	if (pm_runtime_active(scomp->dev))
341 		return sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
342 
343 	return 0;
344 }
345 
346 static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
347 				  const unsigned int __user *binary_data,
348 				  unsigned int size)
349 {
350 	const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data;
351 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
352 	struct snd_soc_component *scomp = scontrol->scomp;
353 	struct snd_ctl_tlv header;
354 
355 	/*
356 	 * The beginning of bytes data contains a header from where
357 	 * the length (as bytes) is needed to know the correct copy
358 	 * length of data from tlvd->tlv.
359 	 */
360 	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
361 		return -EFAULT;
362 
363 	/* make sure TLV info is consistent */
364 	if (header.length + sizeof(struct snd_ctl_tlv) > size) {
365 		dev_err_ratelimited(scomp->dev, "Inconsistent TLV, data %d + header %zu > %d\n",
366 				    header.length, sizeof(struct snd_ctl_tlv), size);
367 		return -EINVAL;
368 	}
369 
370 	/* be->max is coming from topology */
371 	if (header.length > scontrol->max_size) {
372 		dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
373 				    header.length, scontrol->max_size);
374 		return -EINVAL;
375 	}
376 
377 	/* Check that header id matches the command */
378 	if (header.numid != cdata->cmd) {
379 		dev_err_ratelimited(scomp->dev, "Incorrect command for bytes put %d\n",
380 				    header.numid);
381 		return -EINVAL;
382 	}
383 
384 	if (copy_from_user(cdata->data, tlvd->tlv, header.length))
385 		return -EFAULT;
386 
387 	if (cdata->data->magic != SOF_ABI_MAGIC) {
388 		dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic);
389 		return -EINVAL;
390 	}
391 
392 	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
393 		dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n",
394 				    cdata->data->abi);
395 		return -EINVAL;
396 	}
397 
398 	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
399 	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
400 		dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
401 		return -EINVAL;
402 	}
403 
404 	/* notify DSP of byte control updates */
405 	if (pm_runtime_active(scomp->dev))
406 		return sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
407 
408 	return 0;
409 }
410 
411 static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
412 				   const unsigned int __user *binary_data,
413 				   unsigned int size, bool from_dsp)
414 {
415 	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
416 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
417 	struct snd_soc_component *scomp = scontrol->scomp;
418 	struct snd_ctl_tlv header;
419 	size_t data_size;
420 
421 	/*
422 	 * Decrement the limit by ext bytes header size to
423 	 * ensure the user space buffer is not exceeded.
424 	 */
425 	if (size < sizeof(struct snd_ctl_tlv))
426 		return -ENOSPC;
427 
428 	size -= sizeof(struct snd_ctl_tlv);
429 
430 	/* set the ABI header values */
431 	cdata->data->magic = SOF_ABI_MAGIC;
432 	cdata->data->abi = SOF_ABI_VERSION;
433 
434 	/* get all the component data from DSP */
435 	if (from_dsp) {
436 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true);
437 
438 		if (ret < 0)
439 			return ret;
440 	}
441 
442 	/* check data size doesn't exceed max coming from topology */
443 	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
444 		dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
445 				    cdata->data->size,
446 				    scontrol->max_size - sizeof(struct sof_abi_hdr));
447 		return -EINVAL;
448 	}
449 
450 	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
451 
452 	/* make sure we don't exceed size provided by user space for data */
453 	if (data_size > size)
454 		return -ENOSPC;
455 
456 	header.numid = cdata->cmd;
457 	header.length = data_size;
458 	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
459 		return -EFAULT;
460 
461 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
462 		return -EFAULT;
463 
464 	return 0;
465 }
466 
467 static int sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
468 				  const unsigned int __user *binary_data, unsigned int size)
469 {
470 	return _sof_ipc3_bytes_ext_get(scontrol, binary_data, size, false);
471 }
472 
473 static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
474 					   const unsigned int __user *binary_data,
475 					   unsigned int size)
476 {
477 	return _sof_ipc3_bytes_ext_get(scontrol, binary_data, size, true);
478 }
479 
480 static void snd_sof_update_control(struct snd_sof_control *scontrol,
481 				   struct sof_ipc_ctrl_data *cdata)
482 {
483 	struct snd_soc_component *scomp = scontrol->scomp;
484 	struct sof_ipc_ctrl_data *local_cdata;
485 	int i;
486 
487 	local_cdata = scontrol->ipc_control_data;
488 
489 	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
490 		if (cdata->num_elems != local_cdata->data->size) {
491 			dev_err(scomp->dev, "cdata binary size mismatch %u - %u\n",
492 				cdata->num_elems, local_cdata->data->size);
493 			return;
494 		}
495 
496 		/* copy the new binary data */
497 		memcpy(local_cdata->data, cdata->data, cdata->num_elems);
498 	} else if (cdata->num_elems != scontrol->num_channels) {
499 		dev_err(scomp->dev, "cdata channel count mismatch %u - %d\n",
500 			cdata->num_elems, scontrol->num_channels);
501 	} else {
502 		/* copy the new values */
503 		for (i = 0; i < cdata->num_elems; i++)
504 			local_cdata->chanv[i].value = cdata->chanv[i].value;
505 	}
506 }
507 
508 static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message)
509 {
510 	struct sof_ipc_ctrl_data *cdata = ipc_control_message;
511 	struct snd_soc_dapm_widget *widget;
512 	struct snd_sof_control *scontrol;
513 	struct snd_sof_widget *swidget;
514 	struct snd_kcontrol *kc = NULL;
515 	struct soc_mixer_control *sm;
516 	struct soc_bytes_ext *be;
517 	size_t expected_size;
518 	struct soc_enum *se;
519 	bool found = false;
520 	int i, type;
521 
522 	if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET ||
523 	    cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) {
524 		dev_err(sdev->dev, "Component data is not supported in control notification\n");
525 		return;
526 	}
527 
528 	/* Find the swidget first */
529 	list_for_each_entry(swidget, &sdev->widget_list, list) {
530 		if (swidget->comp_id == cdata->comp_id) {
531 			found = true;
532 			break;
533 		}
534 	}
535 
536 	if (!found)
537 		return;
538 
539 	/* Translate SOF cmd to TPLG type */
540 	switch (cdata->cmd) {
541 	case SOF_CTRL_CMD_VOLUME:
542 	case SOF_CTRL_CMD_SWITCH:
543 		type = SND_SOC_TPLG_TYPE_MIXER;
544 		break;
545 	case SOF_CTRL_CMD_BINARY:
546 		type = SND_SOC_TPLG_TYPE_BYTES;
547 		break;
548 	case SOF_CTRL_CMD_ENUM:
549 		type = SND_SOC_TPLG_TYPE_ENUM;
550 		break;
551 	default:
552 		dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__);
553 		return;
554 	}
555 
556 	widget = swidget->widget;
557 	for (i = 0; i < widget->num_kcontrols; i++) {
558 		/* skip non matching types or non matching indexes within type */
559 		if (widget->dobj.widget.kcontrol_type[i] == type &&
560 		    widget->kcontrol_news[i].index == cdata->index) {
561 			kc = widget->kcontrols[i];
562 			break;
563 		}
564 	}
565 
566 	if (!kc)
567 		return;
568 
569 	switch (cdata->cmd) {
570 	case SOF_CTRL_CMD_VOLUME:
571 	case SOF_CTRL_CMD_SWITCH:
572 		sm = (struct soc_mixer_control *)kc->private_value;
573 		scontrol = sm->dobj.private;
574 		break;
575 	case SOF_CTRL_CMD_BINARY:
576 		be = (struct soc_bytes_ext *)kc->private_value;
577 		scontrol = be->dobj.private;
578 		break;
579 	case SOF_CTRL_CMD_ENUM:
580 		se = (struct soc_enum *)kc->private_value;
581 		scontrol = se->dobj.private;
582 		break;
583 	default:
584 		return;
585 	}
586 
587 	expected_size = sizeof(struct sof_ipc_ctrl_data);
588 	switch (cdata->type) {
589 	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
590 	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
591 		expected_size += cdata->num_elems *
592 				 sizeof(struct sof_ipc_ctrl_value_chan);
593 		break;
594 	case SOF_CTRL_TYPE_DATA_GET:
595 	case SOF_CTRL_TYPE_DATA_SET:
596 		expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr);
597 		break;
598 	default:
599 		return;
600 	}
601 
602 	if (cdata->rhdr.hdr.size != expected_size) {
603 		dev_err(sdev->dev, "Component notification size mismatch\n");
604 		return;
605 	}
606 
607 	if (cdata->num_elems)
608 		/*
609 		 * The message includes the updated value/data, update the
610 		 * control's local cache using the received notification
611 		 */
612 		snd_sof_update_control(scontrol, cdata);
613 	else
614 		/* Mark the scontrol that the value/data is changed in SOF */
615 		scontrol->comp_data_dirty = true;
616 
617 	snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
618 }
619 
620 static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev,
621 					  struct snd_sof_widget *swidget)
622 {
623 	struct snd_sof_control *scontrol;
624 	int ret;
625 
626 	/* set up all controls for the widget */
627 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
628 		if (scontrol->comp_id == swidget->comp_id) {
629 			/* set kcontrol data in DSP */
630 			ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, false);
631 			if (ret < 0) {
632 				dev_err(sdev->dev,
633 					"kcontrol %d set up failed for widget %s\n",
634 					scontrol->comp_id, swidget->widget->name);
635 				return ret;
636 			}
637 
638 			/*
639 			 * Read back the data from the DSP for static widgets.
640 			 * This is particularly useful for binary kcontrols
641 			 * associated with static pipeline widgets to initialize
642 			 * the data size to match that in the DSP.
643 			 */
644 			if (swidget->dynamic_pipeline_widget)
645 				continue;
646 
647 			ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, false);
648 			if (ret < 0)
649 				dev_warn(sdev->dev,
650 					 "kcontrol %d read failed for widget %s\n",
651 					 scontrol->comp_id, swidget->widget->name);
652 		}
653 
654 	return 0;
655 }
656 
657 static int
658 sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
659 {
660 	int i;
661 
662 	/* init the volume table */
663 	scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
664 	if (!scontrol->volume_table)
665 		return -ENOMEM;
666 
667 	/* populate the volume table */
668 	for (i = 0; i < size ; i++)
669 		scontrol->volume_table[i] = vol_compute_gain(i, tlv);
670 
671 	return 0;
672 }
673 
674 const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
675 	.volume_put = sof_ipc3_volume_put,
676 	.volume_get = sof_ipc3_volume_get,
677 	.switch_put = sof_ipc3_switch_put,
678 	.switch_get = sof_ipc3_switch_get,
679 	.enum_put = sof_ipc3_enum_put,
680 	.enum_get = sof_ipc3_enum_get,
681 	.bytes_put = sof_ipc3_bytes_put,
682 	.bytes_get = sof_ipc3_bytes_get,
683 	.bytes_ext_put = sof_ipc3_bytes_ext_put,
684 	.bytes_ext_get = sof_ipc3_bytes_ext_get,
685 	.bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
686 	.update = sof_ipc3_control_update,
687 	.widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
688 	.set_up_volume_table = sof_ipc3_set_up_volume_table,
689 };
690