int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base);
+int cs35l56_stash_calibration(struct cs35l56_base *cs35l56_base,
+ const struct cirrus_amp_cal_data *data);
ssize_t cs35l56_calibrate_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, "SND_SOC_CS35L56_SHARED");
-static int cs35l56_stash_calibration(struct cs35l56_base *cs35l56_base,
- const struct cirrus_amp_cal_data *data)
+int cs35l56_stash_calibration(struct cs35l56_base *cs35l56_base,
+ const struct cirrus_amp_cal_data *data)
{
/* Ignore if it is empty */
return 0;
}
+EXPORT_SYMBOL_NS_GPL(cs35l56_stash_calibration, "SND_SOC_CS35L56_SHARED");
static int cs35l56_perform_calibration(struct cs35l56_base *cs35l56_base)
{
},
};
+static int cs35l56_cal_data_rb_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ if (!cs35l56->base.cal_data_valid)
+ return -ENODATA;
+
+ memcpy(ucontrol->value.bytes.data, &cs35l56->base.cal_data,
+ sizeof(cs35l56->base.cal_data));
+
+ return 0;
+}
+
+static int cs35l56_cal_data_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ /*
+ * This control is write-only but mixer libraries often try to read
+ * a control before writing it. So we have to implement read.
+ * Return zeros so a write of valid data will always be a change
+ * from its "current value".
+ */
+ memset(ucontrol->value.bytes.data, 0, sizeof(cs35l56->base.cal_data));
+
+ return 0;
+}
+
+static int cs35l56_cal_data_ctl_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ const struct cirrus_amp_cal_data *cal_data = (const void *)ucontrol->value.bytes.data;
+ int ret;
+
+ if (cs35l56->base.cal_data_valid)
+ return -EACCES;
+
+ ret = cs35l56_stash_calibration(&cs35l56->base, cal_data);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_new_cal_data_apply(cs35l56);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = {
+ SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32),
+ cs35l56_cal_data_ctl_get, cs35l56_cal_data_ctl_set),
+ SND_SOC_BYTES_E("CAL_DATA_RB", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32),
+ cs35l56_cal_data_rb_ctl_get, NULL),
+};
+
static int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)
{
if (cs35l56->dsp.fwf_suffix)
break;
}
+ if (!ret && IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_SET_CTRL)) {
+ ret = snd_soc_add_component_controls(component,
+ cs35l56_cal_data_restore_controls,
+ ARRAY_SIZE(cs35l56_cal_data_restore_controls));
+ }
+
if (ret)
return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n");