0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "sof-priv.h"
0011 #include "sof-audio.h"
0012 #include "ipc4-priv.h"
0013 #include "ipc4-topology.h"
0014
0015 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
0016 {
0017 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
0018 struct snd_soc_component *scomp = scontrol->scomp;
0019 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
0020 const struct sof_ipc_ops *iops = sdev->ipc->ops;
0021 struct sof_ipc4_msg *msg = &cdata->msg;
0022 struct snd_sof_widget *swidget;
0023 bool widget_found = false;
0024
0025
0026 list_for_each_entry(swidget, &sdev->widget_list, list) {
0027 if (swidget->comp_id == scontrol->comp_id) {
0028 widget_found = true;
0029 break;
0030 }
0031 }
0032
0033 if (!widget_found) {
0034 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
0035 return -ENOENT;
0036 }
0037
0038
0039
0040
0041
0042
0043 if (!swidget->use_count)
0044 return 0;
0045
0046 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
0047 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
0048
0049 return iops->set_get_data(sdev, msg, msg->data_size, set);
0050 }
0051
0052 static int
0053 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
0054 struct snd_sof_control *scontrol)
0055 {
0056 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
0057 struct sof_ipc4_gain *gain = swidget->private;
0058 struct sof_ipc4_msg *msg = &cdata->msg;
0059 struct sof_ipc4_gain_data data;
0060 bool all_channels_equal = true;
0061 u32 value;
0062 int ret, i;
0063
0064
0065 value = cdata->chanv[0].value;
0066 for (i = 1; i < scontrol->num_channels; i++) {
0067 if (cdata->chanv[i].value != value) {
0068 all_channels_equal = false;
0069 break;
0070 }
0071 }
0072
0073
0074
0075
0076
0077 for (i = 0; i < scontrol->num_channels; i++) {
0078 if (all_channels_equal) {
0079 data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
0080 data.init_val = cdata->chanv[0].value;
0081 } else {
0082 data.channels = cdata->chanv[i].channel;
0083 data.init_val = cdata->chanv[i].value;
0084 }
0085
0086
0087 data.curve_duration = gain->data.curve_duration;
0088 data.curve_type = gain->data.curve_type;
0089
0090 msg->data_ptr = &data;
0091 msg->data_size = sizeof(data);
0092
0093 ret = sof_ipc4_set_get_kcontrol_data(scontrol, true);
0094 msg->data_ptr = NULL;
0095 msg->data_size = 0;
0096 if (ret < 0) {
0097 dev_err(sdev->dev, "Failed to set volume update for %s\n",
0098 scontrol->name);
0099 return ret;
0100 }
0101
0102 if (all_channels_equal)
0103 break;
0104 }
0105
0106 return 0;
0107 }
0108
0109 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
0110 struct snd_ctl_elem_value *ucontrol)
0111 {
0112 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
0113 struct snd_soc_component *scomp = scontrol->scomp;
0114 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
0115 unsigned int channels = scontrol->num_channels;
0116 struct snd_sof_widget *swidget;
0117 bool widget_found = false;
0118 bool change = false;
0119 unsigned int i;
0120 int ret;
0121
0122
0123 for (i = 0; i < channels; i++) {
0124 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
0125 scontrol->volume_table, scontrol->max + 1);
0126
0127 change = change || (value != cdata->chanv[i].value);
0128 cdata->chanv[i].channel = i;
0129 cdata->chanv[i].value = value;
0130 }
0131
0132 if (!pm_runtime_active(scomp->dev))
0133 return change;
0134
0135
0136 list_for_each_entry(swidget, &sdev->widget_list, list) {
0137 if (swidget->comp_id == scontrol->comp_id) {
0138 widget_found = true;
0139 break;
0140 }
0141 }
0142
0143 if (!widget_found) {
0144 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
0145 return false;
0146 }
0147
0148 ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
0149 if (ret < 0)
0150 return false;
0151
0152 return change;
0153 }
0154
0155 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
0156 struct snd_ctl_elem_value *ucontrol)
0157 {
0158 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
0159 unsigned int channels = scontrol->num_channels;
0160 unsigned int i;
0161
0162 for (i = 0; i < channels; i++)
0163 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
0164 scontrol->volume_table,
0165 scontrol->max + 1);
0166
0167 return 0;
0168 }
0169
0170
0171 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
0172 {
0173 struct snd_sof_control *scontrol;
0174 int ret;
0175
0176 list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
0177 if (scontrol->comp_id == swidget->comp_id) {
0178 ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
0179 if (ret < 0) {
0180 dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n",
0181 __func__, scontrol->comp_id, swidget->widget->name);
0182 return ret;
0183 }
0184 }
0185
0186 return 0;
0187 }
0188
0189 static int
0190 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
0191 {
0192 int i;
0193
0194
0195 scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
0196 if (!scontrol->volume_table)
0197 return -ENOMEM;
0198
0199
0200 for (i = 0; i < size ; i++) {
0201 u32 val = vol_compute_gain(i, tlv);
0202 u64 q31val = ((u64)val) << 15;
0203
0204 scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
0205 SOF_IPC4_VOL_ZERO_DB : q31val;
0206 }
0207
0208 return 0;
0209 }
0210
0211 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
0212 .volume_put = sof_ipc4_volume_put,
0213 .volume_get = sof_ipc4_volume_get,
0214 .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
0215 .set_up_volume_table = sof_ipc4_set_up_volume_table,
0216 };