mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
ASoC: tas2781: Add a debugfs node for acoustic tuning
"Acoustic Tuning" debugfs node is a bridge to the acoustic tuning tool which can tune the chips' acoustic effect. Signed-off-by: Shenghao Ding <shenghao-ding@ti.com> Link: https://patch.msgid.link/20250507094616.210-1-shenghao-ding@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
0fa382a4f5
commit
d75d38dc46
|
|
@ -159,10 +159,33 @@ struct calidata {
|
||||||
unsigned int cali_dat_sz_per_dev;
|
unsigned int cali_dat_sz_per_dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To enable CONFIG_SND_SOC_TAS2781_ACOUST_I2C will create a bridge to the
|
||||||
|
* acoustic tuning tool which can tune the chips' acoustic effect. Due to the
|
||||||
|
* whole directly exposing the registers, there exist some potential risks. So
|
||||||
|
* this define is invisible in Kconfig, anyone who wants to use acoustic tool
|
||||||
|
* have to edit the source manually.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
#define TASDEV_DATA_PAYLOAD_SIZE 128
|
||||||
|
struct acoustic_data {
|
||||||
|
unsigned char len;
|
||||||
|
unsigned char id;
|
||||||
|
unsigned char addr;
|
||||||
|
unsigned char book;
|
||||||
|
unsigned char page;
|
||||||
|
unsigned char reg;
|
||||||
|
unsigned char data[TASDEV_DATA_PAYLOAD_SIZE];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct tasdevice_priv {
|
struct tasdevice_priv {
|
||||||
struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS];
|
struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS];
|
||||||
struct tasdevice_rca rcabin;
|
struct tasdevice_rca rcabin;
|
||||||
struct calidata cali_data;
|
struct calidata cali_data;
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
struct acoustic_data acou_data;
|
||||||
|
#endif
|
||||||
struct tasdevice_fw *fmw;
|
struct tasdevice_fw *fmw;
|
||||||
struct gpio_desc *speaker_id;
|
struct gpio_desc *speaker_id;
|
||||||
struct gpio_desc *reset;
|
struct gpio_desc *reset;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <linux/crc8.h>
|
#include <linux/crc8.h>
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#endif
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
|
@ -1422,10 +1425,150 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
|
||||||
nctrls < i ? nctrls : i);
|
nctrls < i ? nctrls : i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
/*
|
||||||
|
* This debugfs node is a bridge to the acoustic tuning application
|
||||||
|
* tool which can tune the chips' acoustic effect.
|
||||||
|
*
|
||||||
|
* package structure for PPC3 communications:
|
||||||
|
* Pkg len (1 byte)
|
||||||
|
* Pkg id (1 byte, 'r' or 'w')
|
||||||
|
* Dev id (1 byte, i2c address)
|
||||||
|
* Book id (1 byte)
|
||||||
|
* Page id (1 byte)
|
||||||
|
* Reg id (1 byte)
|
||||||
|
* switch (pkg id) {
|
||||||
|
* case 'w':
|
||||||
|
* 1 byte, length of data to read
|
||||||
|
* case 'r':
|
||||||
|
* data payload (1~128 bytes)
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static ssize_t acoustic_ctl_read(struct file *file, char __user *to,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct snd_soc_component *comp = file->private_data;
|
||||||
|
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
|
||||||
|
struct acoustic_data *p = &tas_priv->acou_data;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (p->id == 'r' && p->len == count && count <= sizeof(*p))
|
||||||
|
ret = simple_read_from_buffer(to, count, ppos, p, p->len);
|
||||||
|
else
|
||||||
|
dev_err(tas_priv->dev, "Not ready for get.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t acoustic_ctl_write(struct file *file,
|
||||||
|
const char __user *from, size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct snd_soc_component *comp = file->private_data;
|
||||||
|
struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
|
||||||
|
struct acoustic_data *p = &priv->acou_data;
|
||||||
|
unsigned int max_pkg_len = sizeof(*p);
|
||||||
|
unsigned char *src;
|
||||||
|
int j, len, reg, val;
|
||||||
|
unsigned short chn;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (count > sizeof(*p)) {
|
||||||
|
dev_err(priv->dev, "count(%u) is larger than max(%u).\n",
|
||||||
|
(unsigned int)count, max_pkg_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
src = memdup_user(from, count);
|
||||||
|
if (IS_ERR(src))
|
||||||
|
return PTR_ERR(src);
|
||||||
|
|
||||||
|
if (src[0] > max_pkg_len && src[0] != count) {
|
||||||
|
dev_err(priv->dev, "pkg(%u), max(%u), count(%u) dismatch.\n",
|
||||||
|
src[0], max_pkg_len, (unsigned int)count);
|
||||||
|
ret = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (src[1]) {
|
||||||
|
case 'r':
|
||||||
|
/* length of data to read */
|
||||||
|
len = src[6];
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
/* Skip 6 bytes for package type and register address */
|
||||||
|
len = src[0] - 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
|
||||||
|
ret = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 1) {
|
||||||
|
dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
|
||||||
|
ret = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < priv->ndev; j++)
|
||||||
|
if (src[2] == priv->tasdevice[j].dev_addr) {
|
||||||
|
chn = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j >= priv->ndev) {
|
||||||
|
dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
|
||||||
|
ret = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = TASDEVICE_REG(src[3], src[4], src[5]);
|
||||||
|
|
||||||
|
guard(mutex)(&priv->codec_lock);
|
||||||
|
|
||||||
|
if (src[1] == 'w') {
|
||||||
|
if (len > 1)
|
||||||
|
ret = tasdevice_dev_bulk_write(priv, chn, reg,
|
||||||
|
&src[6], len);
|
||||||
|
else
|
||||||
|
ret = tasdevice_dev_write(priv, chn, reg, src[6]);
|
||||||
|
} else {
|
||||||
|
struct acoustic_data *p = &priv->acou_data;
|
||||||
|
|
||||||
|
memcpy(p, src, 6);
|
||||||
|
if (len > 1) {
|
||||||
|
ret = tasdevice_dev_bulk_read(priv, chn, reg,
|
||||||
|
p->data, len);
|
||||||
|
} else {
|
||||||
|
ret = tasdevice_dev_read(priv, chn, reg, &val);
|
||||||
|
p->data[0] = val;
|
||||||
|
}
|
||||||
|
p->len = len + 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
dev_err(priv->dev, "i2c communication error.\n");
|
||||||
|
else
|
||||||
|
ret = count;
|
||||||
|
exit:
|
||||||
|
kfree(src);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations acoustic_ctl_fops = {
|
||||||
|
.open = simple_open,
|
||||||
|
.read = acoustic_ctl_read,
|
||||||
|
.write = acoustic_ctl_write,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static void tasdevice_fw_ready(const struct firmware *fmw,
|
static void tasdevice_fw_ready(const struct firmware *fmw,
|
||||||
void *context)
|
void *context)
|
||||||
{
|
{
|
||||||
struct tasdevice_priv *tas_priv = context;
|
struct tasdevice_priv *tas_priv = context;
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
struct snd_soc_component *comp = tas_priv->codec;
|
||||||
|
struct dentry *debugfs_root = comp->debugfs_root;
|
||||||
|
char *acoustic_debugfs_node;
|
||||||
|
#endif
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -1499,6 +1642,17 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
|
||||||
|
|
||||||
tasdevice_prmg_load(tas_priv, 0);
|
tasdevice_prmg_load(tas_priv, 0);
|
||||||
tas_priv->cur_prog = 0;
|
tas_priv->cur_prog = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
|
||||||
|
if (tas_priv->name_prefix)
|
||||||
|
acoustic_debugfs_node = devm_kasprintf(tas_priv->dev,
|
||||||
|
GFP_KERNEL, "%s_acoustic_ctl", tas_priv->name_prefix);
|
||||||
|
else
|
||||||
|
acoustic_debugfs_node = devm_kstrdup(tas_priv->dev,
|
||||||
|
"acoustic_ctl", GFP_KERNEL);
|
||||||
|
debugfs_create_file(acoustic_debugfs_node, 0644, debugfs_root,
|
||||||
|
comp, &acoustic_ctl_fops);
|
||||||
|
#endif
|
||||||
out:
|
out:
|
||||||
if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
|
if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
|
||||||
/* If DSP FW fail, DSP kcontrol won't be created. */
|
/* If DSP FW fail, DSP kcontrol won't be created. */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user