| @@ -1109,6 +1109,88 @@ static int cs35l56_cal_data_ctl_set(struct snd_kcontrol *kcontrol, · 1108 unmodified lines |
| 1109 | return 1; | 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 | static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = { | 1194 | static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = { |
| 1113 | SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32), | 1195 | SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32), |
| 1114 | cs35l56_cal_data_ctl_get, cs35l56_cal_data_ctl_set), | 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 | SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE), | 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 | VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56) | 1210 | VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56) |
| 1121 | { | 1211 | { |
| 1122 | unsigned short vendor, device; | 1212 | unsigned short vendor, device; |
| @@ -1290,6 +1380,12 @@ static int cs35l56_component_probe(struct snd_soc_component *component) · 167 unmodified lines |
| 1290 | ARRAY_SIZE(cs35l56_cal_data_restore_controls)); | 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 | if (ret) | 1389 | if (ret) |
| 1294 | return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n"); | 1390 | return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n"); |
| 1295 | | 1391 | |