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