#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
SND_SOC_DAPM_SIGGEN("VDDBMON ADC"),
SND_SOC_DAPM_SIGGEN("VBSTMON ADC"),
SND_SOC_DAPM_SIGGEN("TEMPMON ADC"),
+
+ SND_SOC_DAPM_INPUT("Calibrate"),
};
#define CS35L56_SRC_ROUTE(name) \
{ "DSP1", NULL, "ASP1RX1" },
{ "DSP1", NULL, "ASP1RX2" },
{ "DSP1", NULL, "SDW1 Playback" },
+ { "DSP1", NULL, "Calibrate" },
{ "AMP", NULL, "DSP1" },
{ "SPK", NULL, "AMP" },
pm_runtime_put_autosuspend(cs35l56->base.dev);
}
+static struct snd_soc_dapm_context *cs35l56_power_up_for_cal(struct cs35l56_private *cs35l56)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
+ int ret;
+
+ ret = snd_soc_component_enable_pin(cs35l56->component, "Calibrate");
+ if (ret)
+ return ERR_PTR(ret);
+
+ snd_soc_dapm_sync(dapm);
+
+ return dapm;
+}
+
+static void cs35l56_power_down_after_cal(struct cs35l56_private *cs35l56)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
+
+ snd_soc_component_disable_pin(cs35l56->component, "Calibrate");
+ snd_soc_dapm_sync(dapm);
+}
+
+static ssize_t cs35l56_debugfs_calibrate_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = cs35l56_calibrate_debugfs_write(&cs35l56->base, from, count, ppos);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
+}
+
+static ssize_t cs35l56_debugfs_cal_temperature_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ ret = cs35l56_cal_ambient_debugfs_write(&cs35l56->base, from, count, ppos);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
+}
+
+static ssize_t cs35l56_debugfs_cal_data_read(struct file *file,
+ char __user *to,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ ret = cs35l56_cal_data_debugfs_read(&cs35l56->base, to, count, ppos);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
+}
+
+static int cs35l56_new_cal_data_apply(struct cs35l56_private *cs35l56)
+{
+ struct snd_soc_dapm_context *dapm;
+ int ret;
+
+ if (!cs35l56->base.cal_data_valid)
+ return -ENXIO;
+
+ if (cs35l56->base.secured)
+ return -EACCES;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = cs_amp_write_cal_coeffs(&cs35l56->dsp.cs_dsp,
+ cs35l56->base.calibration_controls,
+ &cs35l56->base.cal_data);
+ if (ret == 0)
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ else
+ ret = -EIO;
+
+ snd_soc_dapm_mutex_unlock(dapm);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
+}
+
+static ssize_t cs35l56_debugfs_cal_data_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ int ret;
+
+ ret = cs35l56_cal_data_debugfs_write(&cs35l56->base, from, count, ppos);
+ if (ret == -ENODATA)
+ return count; /* Ignore writes of empty cal blobs */
+ else if (ret < 0)
+ return -EIO;
+
+ ret = cs35l56_new_cal_data_apply(cs35l56);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static const struct cs35l56_cal_debugfs_fops cs35l56_cal_debugfs_fops = {
+ .calibrate = {
+ .write = cs35l56_debugfs_calibrate_write,
+ },
+ .cal_temperature = {
+ .write = cs35l56_debugfs_cal_temperature_write,
+ },
+ .cal_data = {
+ .read = cs35l56_debugfs_cal_data_read,
+ .write = cs35l56_debugfs_cal_data_write,
+ },
+};
+
static int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)
{
if (cs35l56->dsp.fwf_suffix)
if (ret)
return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n");
+ ret = snd_soc_component_disable_pin(component, "Calibrate");
+ if (ret)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS))
+ cs35l56_create_cal_debugfs(&cs35l56->base, &cs35l56_cal_debugfs_fops);
+
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
return 0;
cancel_work_sync(&cs35l56->dsp_work);
+ cs35l56_remove_cal_debugfs(&cs35l56->base);
+
if (cs35l56->dsp.cs_dsp.booted)
wm_adsp_power_down(&cs35l56->dsp);