| @@ -1109,6 +1109,88 @@ static int cs35l56_cal_data_ctl_set(struct snd_kcontrol *kcontrol, · 1108 unmodified lines |
| 1109 | 1109 | return 1; |
| 1110 | 1110 | } |
| 1111 | 1111 | |
| 1112 | +static int cs35l56_cal_ambient_ctl_get(struct snd_kcontrol *kcontrol, |
| 1113 | + struct snd_ctl_elem_value *ucontrol) |
| 1114 | +{ |
| 1115 | + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 1116 | + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); |
| 1117 | + |
| 1118 | + ucontrol->value.integer.value[0] = cs35l56->ambient_ctl_value; |
| 1119 | + |
| 1120 | + return 0; |
| 1121 | +} |
| 1122 | + |
| 1123 | +static int cs35l56_cal_ambient_ctl_set(struct snd_kcontrol *kcontrol, |
| 1124 | + struct snd_ctl_elem_value *ucontrol) |
| 1125 | +{ |
| 1126 | + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 1127 | + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); |
| 1128 | + struct snd_soc_dapm_context *dapm; |
| 1129 | + int temperature = ucontrol->value.integer.value[0]; |
| 1130 | + int ret; |
| 1131 | + |
| 1132 | + if (temperature == cs35l56->ambient_ctl_value) |
| 1133 | + return 0; |
| 1134 | + |
| 1135 | + if ((temperature < 0) || (temperature > 40)) |
| 1136 | + return -EINVAL; |
| 1137 | + |
| 1138 | + dapm = cs35l56_power_up_for_cal(cs35l56); |
| 1139 | + if (IS_ERR(dapm)) |
| 1140 | + return PTR_ERR(dapm); |
| 1141 | + |
| 1142 | + ret = cs_amp_write_ambient_temp(&cs35l56->dsp.cs_dsp, |
| 1143 | + cs35l56->base.calibration_controls, |
| 1144 | + temperature); |
| 1145 | + cs35l56_power_down_after_cal(cs35l56); |
| 1146 | + |
| 1147 | + if (ret) |
| 1148 | + return ret; |
| 1149 | + |
| 1150 | + cs35l56->ambient_ctl_value = temperature; |
| 1151 | + |
| 1152 | + return 1; |
| 1153 | +} |
| 1154 | + |
| 1155 | +static int cs35l56_calibrate_ctl_get(struct snd_kcontrol *kcontrol, |
| 1156 | + struct snd_ctl_elem_value *ucontrol) |
| 1157 | +{ |
| 1158 | + /* |
| 1159 | + * Allow reading because of user-side libraries that assume all |
| 1160 | + * controls are readable. But always return false to prevent dumb |
| 1161 | + * save-restore tools like alsactl accidentically triggering a |
| 1162 | + * factory calibration when they restore. |
| 1163 | + */ |
| 1164 | + ucontrol->value.integer.value[0] = 0; |
| 1165 | + |
| 1166 | + return 0; |
| 1167 | +} |
| 1168 | + |
| 1169 | +static int cs35l56_calibrate_ctl_set(struct snd_kcontrol *kcontrol, |
| 1170 | + struct snd_ctl_elem_value *ucontrol) |
| 1171 | +{ |
| 1172 | + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 1173 | + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); |
| 1174 | + struct snd_soc_dapm_context *dapm; |
| 1175 | + int ret; |
| 1176 | + |
| 1177 | + if (ucontrol->value.integer.value[0] == 0) |
| 1178 | + return 0; |
| 1179 | + |
| 1180 | + dapm = cs35l56_power_up_for_cal(cs35l56); |
| 1181 | + if (IS_ERR(dapm)) |
| 1182 | + return PTR_ERR(dapm); |
| 1183 | + |
| 1184 | + snd_soc_dapm_mutex_lock(dapm); |
| 1185 | + ret = cs35l56_factory_calibrate(&cs35l56->base); |
| 1186 | + snd_soc_dapm_mutex_unlock(dapm); |
| 1187 | + cs35l56_power_down_after_cal(cs35l56); |
| 1188 | + if (ret < 0) |
| 1189 | + return ret; |
| 1190 | + |
| 1191 | + return 1; |
| 1192 | +} |
| 1193 | + |
| 1112 | 1194 | static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = { |
| 1113 | 1195 | SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32), |
| 1114 | 1196 | cs35l56_cal_data_ctl_get, cs35l56_cal_data_ctl_set), |
| @@ -1117,6 +1199,14 @@ static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = { · 2 unmodified lines |
| 1117 | 1199 | SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE), |
| 1118 | 1200 | }; |
| 1119 | 1201 | |
| 1202 | +static const struct snd_kcontrol_new cs35l56_cal_perform_controls[] = { |
| 1203 | + SOC_SINGLE_EXT("CAL_AMBIENT", SND_SOC_NOPM, 0, 40, 0, |
| 1204 | + cs35l56_cal_ambient_ctl_get, cs35l56_cal_ambient_ctl_set), |
| 1205 | + SOC_SINGLE_BOOL_EXT_ACC("Calibrate Switch", 0, |
| 1206 | + cs35l56_calibrate_ctl_get, cs35l56_calibrate_ctl_set, |
| 1207 | + SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE), |
| 1208 | +}; |
| 1209 | + |
| 1120 | 1210 | VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56) |
| 1121 | 1211 | { |
| 1122 | 1212 | unsigned short vendor, device; |
| @@ -1290,6 +1380,12 @@ static int cs35l56_component_probe(struct snd_soc_component *component) · 167 unmodified lines |
| 1290 | 1380 | ARRAY_SIZE(cs35l56_cal_data_restore_controls)); |
| 1291 | 1381 | } |
| 1292 | 1382 | |
| 1383 | + if (!ret && IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_PERFORM_CTRL)) { |
| 1384 | + ret = snd_soc_add_component_controls(component, |
| 1385 | + cs35l56_cal_perform_controls, |
| 1386 | + ARRAY_SIZE(cs35l56_cal_perform_controls)); |
| 1387 | + } |
| 1388 | + |
| 1293 | 1389 | if (ret) |
| 1294 | 1390 | return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n"); |
| 1295 | 1391 | |