History

ASoC: cs35l56: Allow factory calibration through ALSA controls

Add support for using ALSA controls to trigger a factory calibration. This is protected by a new Kconfig option so that it is only available if explicitly enabled in the kernel. By default it is not enabled. Factory calibration is normally done through debugfs files. Google have requested that factory calibration can be performed by repair shops. These repair shops only have access to the standard "user" kernel, which does not include debugfs.

Richard Fitzgerald committed 7 months ago

Commit ee7d6551 parent 37c277f5 files · +121 −0Browse files

Unified · Split

5 files
  1. include/sound/cs35l56.h +1 −0
  2. sound/soc/codecs/Kconfig +13 −0
  3. sound/soc/codecs/cs35l56-shared.c +9 −0
  4. sound/soc/codecs/cs35l56.c +96 −0
  5. sound/soc/codecs/cs35l56.h +2 −0
include/sound/cs35l56.h+1−0
@@ -435,6 +435,7 @@ ssize_t cs35l56_cal_data_debugfs_read(struct cs35l56_base *cs35l56_base, · 434 unmodified lines
435ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,435ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,
436 const char __user *from, size_t count,436 const char __user *from, size_t count,
437 loff_t *ppos);437 loff_t *ppos);
438int cs35l56_factory_calibrate(struct cs35l56_base *cs35l56_base);
438void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base,439void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base,
439 const struct cs35l56_cal_debugfs_fops *fops);440 const struct cs35l56_cal_debugfs_fops *fops);
440void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base);441void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base);
sound/soc/codecs/Kconfig+13−0
@@ -928,6 +928,19 @@ config SND_SOC_CS35L56_CAL_SET_CTRL · 927 unmodified lines
928 928
929 If unsure select "N".929 If unsure select "N".
930 930
931config SND_SOC_CS35L56_CAL_PERFORM_CTRL
932 bool "CS35L56 ALSA control to perform factory calibration"
933 default N
934 select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
935 help
936 Allow performing factory calibration data through an ALSA
937 control. It is recommended to use the debugfs method instead
938 because debugfs has restricted access permissions.
939
940 On most platforms this is not needed.
941
942 If unsure select "N".
943
931config SND_SOC_CS35L56_TEST944config SND_SOC_CS35L56_TEST
932 tristate "KUnit test for Cirrus Logic cs35l56 driver" if !KUNIT_ALL_TESTS945 tristate "KUnit test for Cirrus Logic cs35l56 driver" if !KUNIT_ALL_TESTS
933 depends on SND_SOC_CS35L56 && KUNIT946 depends on SND_SOC_CS35L56 && KUNIT
sound/soc/codecs/cs35l56-shared.c+9−0
@@ -1185,6 +1185,15 @@ ssize_t cs35l56_calibrate_debugfs_write(struct cs35l56_base *cs35l56_base, · 1184 unmodified lines
1185}1185}
1186EXPORT_SYMBOL_NS_GPL(cs35l56_calibrate_debugfs_write, "SND_SOC_CS35L56_SHARED");1186EXPORT_SYMBOL_NS_GPL(cs35l56_calibrate_debugfs_write, "SND_SOC_CS35L56_SHARED");
1187 1187
1188int cs35l56_factory_calibrate(struct cs35l56_base *cs35l56_base)
1189{
1190 if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_PERFORM_CTRL))
1191 return -ENXIO;
1192
1193 return cs35l56_perform_calibration(cs35l56_base);
1194}
1195EXPORT_SYMBOL_NS_GPL(cs35l56_factory_calibrate, "SND_SOC_CS35L56_SHARED");
1196
1188ssize_t cs35l56_cal_ambient_debugfs_write(struct cs35l56_base *cs35l56_base,1197ssize_t cs35l56_cal_ambient_debugfs_write(struct cs35l56_base *cs35l56_base,
1189 const char __user *from, size_t count,1198 const char __user *from, size_t count,
1190 loff_t *ppos)1199 loff_t *ppos)
sound/soc/codecs/cs35l56.c+96−0
@@ -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
1112static 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
1123static 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
1155static 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
1169static 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
1112static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = {1194static 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
1202static 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
1120VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)1210VISIBLE_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
sound/soc/codecs/cs35l56.h+2−0
@@ -53,6 +53,8 @@ struct cs35l56_private { · 52 unmodified lines
53 bool sysclk_set;53 bool sysclk_set;
54 u8 sdw_link_num;54 u8 sdw_link_num;
55 u8 sdw_unique_id;55 u8 sdw_unique_id;
56
57 u8 ambient_ctl_value;
56};58};
57 59
58static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_base *cs35l56_base)60static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_base *cs35l56_base)