mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 07:03:03 +02:00
ASoC: cs35l56: Create debugfs files for factory calibration
Create debugfs files that can be used to perform factory calibration. During manufacture, the production line must perform a factory calibration of the amps. This patch adds this functionality via debugfs files. As this is only needed during manufacture, there is no need for this to be available in a normal system so a Kconfig item has been added to enable this. The new Kconfig option is inside a sub-menu because items do not group and indent if the parent is invisible or there are multiple parent dependencies. Anyway the sub-menu reduces the clutter. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Reviewed-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20251021105022.1013685-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
f7097161e9
commit
191a27faf5
|
|
@ -899,6 +899,21 @@ config SND_SOC_CS35L56_SDW
|
|||
config SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
|
||||
bool
|
||||
|
||||
menu "CS35L56 driver options"
|
||||
depends on SND_SOC_CS35L56
|
||||
|
||||
config SND_SOC_CS35L56_CAL_DEBUGFS
|
||||
bool "CS35L56 create debugfs for factory calibration"
|
||||
default N
|
||||
depends on DEBUG_FS
|
||||
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
|
||||
help
|
||||
Create debugfs entries used during factory-line manufacture
|
||||
for factory calibration.
|
||||
|
||||
If unsure select "N".
|
||||
endmenu
|
||||
|
||||
config SND_SOC_CS40L50
|
||||
tristate "Cirrus Logic CS40L50 CODEC"
|
||||
depends on MFD_CS40L50_CORE
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#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>
|
||||
|
|
@ -250,6 +251,8 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
|
|||
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) \
|
||||
|
|
@ -286,6 +289,7 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
|
|||
{ "DSP1", NULL, "ASP1RX1" },
|
||||
{ "DSP1", NULL, "ASP1RX2" },
|
||||
{ "DSP1", NULL, "SDW1 Playback" },
|
||||
{ "DSP1", NULL, "Calibrate" },
|
||||
{ "AMP", NULL, "DSP1" },
|
||||
{ "SPK", NULL, "AMP" },
|
||||
|
||||
|
|
@ -874,6 +878,152 @@ static void cs35l56_dsp_work(struct work_struct *work)
|
|||
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)
|
||||
|
|
@ -971,6 +1121,13 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
|
|||
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;
|
||||
|
|
@ -982,6 +1139,8 @@ static void cs35l56_component_remove(struct snd_soc_component *component)
|
|||
|
||||
cancel_work_sync(&cs35l56->dsp_work);
|
||||
|
||||
cs35l56_remove_cal_debugfs(&cs35l56->base);
|
||||
|
||||
if (cs35l56->dsp.cs_dsp.booted)
|
||||
wm_adsp_power_down(&cs35l56->dsp);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#define CS35L56_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
|
@ -54,6 +55,11 @@ struct cs35l56_private {
|
|||
u8 sdw_unique_id;
|
||||
};
|
||||
|
||||
static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_base *cs35l56_base)
|
||||
{
|
||||
return container_of(cs35l56_base, struct cs35l56_private, base);
|
||||
}
|
||||
|
||||
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
|
||||
|
||||
int cs35l56_system_suspend(struct device *dev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user