Linux 6.7-rc7
[linux-modified.git] / sound / soc / sof / ipc4-control.c
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) 2022 Intel Corporation. All rights reserved.
7 //
8 //
9
10 #include "sof-priv.h"
11 #include "sof-audio.h"
12 #include "ipc4-priv.h"
13 #include "ipc4-topology.h"
14
15 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
16                                           bool set, bool lock)
17 {
18         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
19         struct snd_soc_component *scomp = scontrol->scomp;
20         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
21         const struct sof_ipc_ops *iops = sdev->ipc->ops;
22         struct sof_ipc4_msg *msg = &cdata->msg;
23         struct snd_sof_widget *swidget;
24         bool widget_found = false;
25         int ret = 0;
26
27         /* find widget associated with the control */
28         list_for_each_entry(swidget, &sdev->widget_list, list) {
29                 if (swidget->comp_id == scontrol->comp_id) {
30                         widget_found = true;
31                         break;
32                 }
33         }
34
35         if (!widget_found) {
36                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
37                 return -ENOENT;
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         msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
54         msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
55
56         ret = iops->set_get_data(sdev, msg, msg->data_size, set);
57         if (!set)
58                 goto unlock;
59
60         /* It is a set-data operation, and we have a valid backup that we can restore */
61         if (ret < 0) {
62                 if (!scontrol->old_ipc_control_data)
63                         goto unlock;
64                 /*
65                  * Current ipc_control_data is not valid, we use the last known good
66                  * configuration
67                  */
68                 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
69                        scontrol->max_size);
70                 kfree(scontrol->old_ipc_control_data);
71                 scontrol->old_ipc_control_data = NULL;
72                 /* Send the last known good configuration to firmware */
73                 ret = iops->set_get_data(sdev, msg, msg->data_size, set);
74                 if (ret < 0)
75                         goto unlock;
76         }
77
78 unlock:
79         if (lock)
80                 mutex_unlock(&swidget->setup_mutex);
81
82         return ret;
83 }
84
85 static int
86 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
87                          struct snd_sof_control *scontrol, bool lock)
88 {
89         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
90         struct sof_ipc4_gain *gain = swidget->private;
91         struct sof_ipc4_msg *msg = &cdata->msg;
92         struct sof_ipc4_gain_params params;
93         bool all_channels_equal = true;
94         u32 value;
95         int ret, i;
96
97         /* check if all channel values are equal */
98         value = cdata->chanv[0].value;
99         for (i = 1; i < scontrol->num_channels; i++) {
100                 if (cdata->chanv[i].value != value) {
101                         all_channels_equal = false;
102                         break;
103                 }
104         }
105
106         /*
107          * notify DSP with a single IPC message if all channel values are equal. Otherwise send
108          * a separate IPC for each channel.
109          */
110         for (i = 0; i < scontrol->num_channels; i++) {
111                 if (all_channels_equal) {
112                         params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
113                         params.init_val = cdata->chanv[0].value;
114                 } else {
115                         params.channels = cdata->chanv[i].channel;
116                         params.init_val = cdata->chanv[i].value;
117                 }
118
119                 /* set curve type and duration from topology */
120                 params.curve_duration_l = gain->data.params.curve_duration_l;
121                 params.curve_duration_h = gain->data.params.curve_duration_h;
122                 params.curve_type = gain->data.params.curve_type;
123
124                 msg->data_ptr = &params;
125                 msg->data_size = sizeof(params);
126
127                 ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
128                 msg->data_ptr = NULL;
129                 msg->data_size = 0;
130                 if (ret < 0) {
131                         dev_err(sdev->dev, "Failed to set volume update for %s\n",
132                                 scontrol->name);
133                         return ret;
134                 }
135
136                 if (all_channels_equal)
137                         break;
138         }
139
140         return 0;
141 }
142
143 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
144                                 struct snd_ctl_elem_value *ucontrol)
145 {
146         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
147         struct snd_soc_component *scomp = scontrol->scomp;
148         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
149         unsigned int channels = scontrol->num_channels;
150         struct snd_sof_widget *swidget;
151         bool widget_found = false;
152         bool change = false;
153         unsigned int i;
154         int ret;
155
156         /* update each channel */
157         for (i = 0; i < channels; i++) {
158                 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
159                                          scontrol->volume_table, scontrol->max + 1);
160
161                 change = change || (value != cdata->chanv[i].value);
162                 cdata->chanv[i].channel = i;
163                 cdata->chanv[i].value = value;
164         }
165
166         if (!pm_runtime_active(scomp->dev))
167                 return change;
168
169         /* find widget associated with the control */
170         list_for_each_entry(swidget, &sdev->widget_list, list) {
171                 if (swidget->comp_id == scontrol->comp_id) {
172                         widget_found = true;
173                         break;
174                 }
175         }
176
177         if (!widget_found) {
178                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
179                 return false;
180         }
181
182         ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol, true);
183         if (ret < 0)
184                 return false;
185
186         return change;
187 }
188
189 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
190                                struct snd_ctl_elem_value *ucontrol)
191 {
192         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
193         unsigned int channels = scontrol->num_channels;
194         unsigned int i;
195
196         for (i = 0; i < channels; i++)
197                 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
198                                                                 scontrol->volume_table,
199                                                                 scontrol->max + 1);
200
201         return 0;
202 }
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
357 static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
358                                        struct snd_sof_control *scontrol,
359                                        bool set, bool lock)
360 {
361         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
362         struct sof_abi_hdr *data = cdata->data;
363         struct sof_ipc4_msg *msg = &cdata->msg;
364         int ret = 0;
365
366         /* Send the new data to the firmware only if it is powered up */
367         if (set && !pm_runtime_active(sdev->dev))
368                 return 0;
369
370         msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
371
372         msg->data_ptr = data->data;
373         msg->data_size = data->size;
374
375         ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock);
376         if (ret < 0)
377                 dev_err(sdev->dev, "Failed to %s for %s\n",
378                         set ? "set bytes update" : "get bytes",
379                         scontrol->name);
380
381         msg->data_ptr = NULL;
382         msg->data_size = 0;
383
384         return ret;
385 }
386
387 static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
388                               struct snd_ctl_elem_value *ucontrol)
389 {
390         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
391         struct snd_soc_component *scomp = scontrol->scomp;
392         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
393         struct sof_abi_hdr *data = cdata->data;
394         size_t size;
395
396         if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
397                 dev_err_ratelimited(scomp->dev,
398                                     "data max %zu exceeds ucontrol data array size\n",
399                                     scontrol->max_size);
400                 return -EINVAL;
401         }
402
403         /* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
404         if (data->size > scontrol->max_size - sizeof(*data)) {
405                 dev_err_ratelimited(scomp->dev,
406                                     "data size too big %u bytes max is %zu\n",
407                                     data->size, scontrol->max_size - sizeof(*data));
408                 return -EINVAL;
409         }
410
411         size = data->size + sizeof(*data);
412
413         /* copy from kcontrol */
414         memcpy(data, ucontrol->value.bytes.data, size);
415
416         sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
417
418         return 0;
419 }
420
421 static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
422                               struct snd_ctl_elem_value *ucontrol)
423 {
424         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
425         struct snd_soc_component *scomp = scontrol->scomp;
426         struct sof_abi_hdr *data = cdata->data;
427         size_t size;
428
429         if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
430                 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
431                                     scontrol->max_size);
432                 return -EINVAL;
433         }
434
435         if (data->size > scontrol->max_size - sizeof(*data)) {
436                 dev_err_ratelimited(scomp->dev,
437                                     "%u bytes of control data is invalid, max is %zu\n",
438                                     data->size, scontrol->max_size - sizeof(*data));
439                 return -EINVAL;
440         }
441
442         size = data->size + sizeof(*data);
443
444         /* copy back to kcontrol */
445         memcpy(ucontrol->value.bytes.data, data, size);
446
447         return 0;
448 }
449
450 static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
451                                   const unsigned int __user *binary_data,
452                                   unsigned int size)
453 {
454         struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
455         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
456         struct snd_soc_component *scomp = scontrol->scomp;
457         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
458         struct sof_abi_hdr *data = cdata->data;
459         struct sof_abi_hdr abi_hdr;
460         struct snd_ctl_tlv header;
461
462         /*
463          * The beginning of bytes data contains a header from where
464          * the length (as bytes) is needed to know the correct copy
465          * length of data from tlvd->tlv.
466          */
467         if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
468                 return -EFAULT;
469
470         /* make sure TLV info is consistent */
471         if (header.length + sizeof(struct snd_ctl_tlv) > size) {
472                 dev_err_ratelimited(scomp->dev,
473                                     "Inconsistent TLV, data %d + header %zu > %d\n",
474                                     header.length, sizeof(struct snd_ctl_tlv), size);
475                 return -EINVAL;
476         }
477
478         /* be->max is coming from topology */
479         if (header.length > scontrol->max_size) {
480                 dev_err_ratelimited(scomp->dev,
481                                     "Bytes data size %d exceeds max %zu\n",
482                                     header.length, scontrol->max_size);
483                 return -EINVAL;
484         }
485
486         /* Verify the ABI header first */
487         if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
488                 return -EFAULT;
489
490         if (abi_hdr.magic != SOF_IPC4_ABI_MAGIC) {
491                 dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n",
492                                     abi_hdr.magic);
493                 return -EINVAL;
494         }
495
496         if (abi_hdr.size > scontrol->max_size - sizeof(abi_hdr)) {
497                 dev_err_ratelimited(scomp->dev,
498                                     "%u bytes of control data is invalid, max is %zu\n",
499                                     abi_hdr.size, scontrol->max_size - sizeof(abi_hdr));
500                 return -EINVAL;
501         }
502
503         if (!scontrol->old_ipc_control_data) {
504                 /* Create a backup of the current, valid bytes control */
505                 scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data,
506                                                          scontrol->max_size, GFP_KERNEL);
507                 if (!scontrol->old_ipc_control_data)
508                         return -ENOMEM;
509         }
510
511         /* Copy the whole binary data which includes the ABI header and the payload */
512         if (copy_from_user(data, tlvd->tlv, header.length)) {
513                 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
514                        scontrol->max_size);
515                 kfree(scontrol->old_ipc_control_data);
516                 scontrol->old_ipc_control_data = NULL;
517                 return -EFAULT;
518         }
519
520         return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
521 }
522
523 static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
524                                    const unsigned int __user *binary_data,
525                                    unsigned int size, bool from_dsp)
526 {
527         struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
528         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
529         struct snd_soc_component *scomp = scontrol->scomp;
530         struct sof_abi_hdr *data = cdata->data;
531         struct snd_ctl_tlv header;
532         size_t data_size;
533
534         /*
535          * Decrement the limit by ext bytes header size to ensure the user space
536          * buffer is not exceeded.
537          */
538         if (size < sizeof(struct snd_ctl_tlv))
539                 return -ENOSPC;
540
541         size -= sizeof(struct snd_ctl_tlv);
542
543         /* get all the component data from DSP */
544         if (from_dsp) {
545                 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
546                 int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true);
547
548                 if (ret < 0)
549                         return ret;
550
551                 /* Set the ABI magic (if the control is not initialized) */
552                 data->magic = SOF_IPC4_ABI_MAGIC;
553         }
554
555         if (data->size > scontrol->max_size - sizeof(*data)) {
556                 dev_err_ratelimited(scomp->dev,
557                                     "%u bytes of control data is invalid, max is %zu\n",
558                                     data->size, scontrol->max_size - sizeof(*data));
559                 return -EINVAL;
560         }
561
562         data_size = data->size + sizeof(struct sof_abi_hdr);
563
564         /* make sure we don't exceed size provided by user space for data */
565         if (data_size > size)
566                 return -ENOSPC;
567
568         header.numid = scontrol->comp_id;
569         header.length = data_size;
570
571         if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
572                 return -EFAULT;
573
574         if (copy_to_user(tlvd->tlv, data, data_size))
575                 return -EFAULT;
576
577         return 0;
578 }
579
580 static int sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
581                                   const unsigned int __user *binary_data,
582                                   unsigned int size)
583 {
584         return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false);
585 }
586
587 static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
588                                            const unsigned int __user *binary_data,
589                                            unsigned int size)
590 {
591         return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
592 }
593
594 static int
595 sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
596                      struct snd_sof_control *scontrol)
597 {
598         if (scontrol->max == 1)
599                 return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false);
600
601         return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
602 }
603
604 /* set up all controls for the widget */
605 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
606 {
607         struct snd_sof_control *scontrol;
608         int ret = 0;
609
610         list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
611                 if (scontrol->comp_id == swidget->comp_id) {
612                         switch (scontrol->info_type) {
613                         case SND_SOC_TPLG_CTL_VOLSW:
614                         case SND_SOC_TPLG_CTL_VOLSW_SX:
615                         case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
616                                 ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol);
617                                 break;
618                         case SND_SOC_TPLG_CTL_BYTES:
619                                 ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
620                                                                   true, false);
621                                 break;
622                         case SND_SOC_TPLG_CTL_ENUM:
623                         case SND_SOC_TPLG_CTL_ENUM_VALUE:
624                                 ret = sof_ipc4_set_generic_control_data(sdev, swidget,
625                                                                         scontrol, false);
626                                 break;
627                         default:
628                                 break;
629                         }
630
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
640         return 0;
641 }
642
643 static int
644 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
645 {
646         int i;
647
648         /* init the volume table */
649         scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
650         if (!scontrol->volume_table)
651                 return -ENOMEM;
652
653         /* populate the volume table */
654         for (i = 0; i < size ; i++) {
655                 u32 val = vol_compute_gain(i, tlv);
656                 u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
657
658                 scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
659                                                 SOF_IPC4_VOL_ZERO_DB : q31val;
660         }
661
662         return 0;
663 }
664
665 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
666         .volume_put = sof_ipc4_volume_put,
667         .volume_get = sof_ipc4_volume_get,
668         .switch_put = sof_ipc4_switch_put,
669         .switch_get = sof_ipc4_switch_get,
670         .enum_put = sof_ipc4_enum_put,
671         .enum_get = sof_ipc4_enum_get,
672         .bytes_put = sof_ipc4_bytes_put,
673         .bytes_get = sof_ipc4_bytes_get,
674         .bytes_ext_put = sof_ipc4_bytes_ext_put,
675         .bytes_ext_get = sof_ipc4_bytes_ext_get,
676         .bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
677         .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
678         .set_up_volume_table = sof_ipc4_set_up_volume_table,
679 };