Skip to content

Commit d75d38d

Browse files
Shenghao-Dingbroonie
authored andcommitted
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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 0fa382a commit d75d38d

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

include/sound/tas2781.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,33 @@ struct calidata {
159159
unsigned int cali_dat_sz_per_dev;
160160
};
161161

162+
/*
163+
* To enable CONFIG_SND_SOC_TAS2781_ACOUST_I2C will create a bridge to the
164+
* acoustic tuning tool which can tune the chips' acoustic effect. Due to the
165+
* whole directly exposing the registers, there exist some potential risks. So
166+
* this define is invisible in Kconfig, anyone who wants to use acoustic tool
167+
* have to edit the source manually.
168+
*/
169+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
170+
#define TASDEV_DATA_PAYLOAD_SIZE 128
171+
struct acoustic_data {
172+
unsigned char len;
173+
unsigned char id;
174+
unsigned char addr;
175+
unsigned char book;
176+
unsigned char page;
177+
unsigned char reg;
178+
unsigned char data[TASDEV_DATA_PAYLOAD_SIZE];
179+
};
180+
#endif
181+
162182
struct tasdevice_priv {
163183
struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS];
164184
struct tasdevice_rca rcabin;
165185
struct calidata cali_data;
186+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
187+
struct acoustic_data acou_data;
188+
#endif
166189
struct tasdevice_fw *fmw;
167190
struct gpio_desc *speaker_id;
168191
struct gpio_desc *reset;

sound/soc/codecs/tas2781-i2c.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
//
1515

1616
#include <linux/crc8.h>
17+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
18+
#include <linux/debugfs.h>
19+
#endif
1720
#include <linux/firmware.h>
1821
#include <linux/gpio/consumer.h>
1922
#include <linux/i2c.h>
@@ -1422,10 +1425,150 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
14221425
nctrls < i ? nctrls : i);
14231426
}
14241427

1428+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
1429+
/*
1430+
* This debugfs node is a bridge to the acoustic tuning application
1431+
* tool which can tune the chips' acoustic effect.
1432+
*
1433+
* package structure for PPC3 communications:
1434+
* Pkg len (1 byte)
1435+
* Pkg id (1 byte, 'r' or 'w')
1436+
* Dev id (1 byte, i2c address)
1437+
* Book id (1 byte)
1438+
* Page id (1 byte)
1439+
* Reg id (1 byte)
1440+
* switch (pkg id) {
1441+
* case 'w':
1442+
* 1 byte, length of data to read
1443+
* case 'r':
1444+
* data payload (1~128 bytes)
1445+
* }
1446+
*/
1447+
static ssize_t acoustic_ctl_read(struct file *file, char __user *to,
1448+
size_t count, loff_t *ppos)
1449+
{
1450+
struct snd_soc_component *comp = file->private_data;
1451+
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
1452+
struct acoustic_data *p = &tas_priv->acou_data;
1453+
int ret = -1;
1454+
1455+
if (p->id == 'r' && p->len == count && count <= sizeof(*p))
1456+
ret = simple_read_from_buffer(to, count, ppos, p, p->len);
1457+
else
1458+
dev_err(tas_priv->dev, "Not ready for get.\n");
1459+
return ret;
1460+
}
1461+
1462+
static ssize_t acoustic_ctl_write(struct file *file,
1463+
const char __user *from, size_t count, loff_t *ppos)
1464+
{
1465+
struct snd_soc_component *comp = file->private_data;
1466+
struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
1467+
struct acoustic_data *p = &priv->acou_data;
1468+
unsigned int max_pkg_len = sizeof(*p);
1469+
unsigned char *src;
1470+
int j, len, reg, val;
1471+
unsigned short chn;
1472+
int ret = -1;
1473+
1474+
if (count > sizeof(*p)) {
1475+
dev_err(priv->dev, "count(%u) is larger than max(%u).\n",
1476+
(unsigned int)count, max_pkg_len);
1477+
return ret;
1478+
}
1479+
1480+
src = memdup_user(from, count);
1481+
if (IS_ERR(src))
1482+
return PTR_ERR(src);
1483+
1484+
if (src[0] > max_pkg_len && src[0] != count) {
1485+
dev_err(priv->dev, "pkg(%u), max(%u), count(%u) dismatch.\n",
1486+
src[0], max_pkg_len, (unsigned int)count);
1487+
ret = 0;
1488+
goto exit;
1489+
}
1490+
1491+
switch (src[1]) {
1492+
case 'r':
1493+
/* length of data to read */
1494+
len = src[6];
1495+
break;
1496+
case 'w':
1497+
/* Skip 6 bytes for package type and register address */
1498+
len = src[0] - 6;
1499+
break;
1500+
default:
1501+
dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
1502+
ret = 0;
1503+
goto exit;
1504+
}
1505+
1506+
if (len < 1) {
1507+
dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
1508+
ret = 0;
1509+
goto exit;
1510+
}
1511+
1512+
for (j = 0; j < priv->ndev; j++)
1513+
if (src[2] == priv->tasdevice[j].dev_addr) {
1514+
chn = j;
1515+
break;
1516+
}
1517+
if (j >= priv->ndev) {
1518+
dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
1519+
ret = 0;
1520+
goto exit;
1521+
}
1522+
1523+
reg = TASDEVICE_REG(src[3], src[4], src[5]);
1524+
1525+
guard(mutex)(&priv->codec_lock);
1526+
1527+
if (src[1] == 'w') {
1528+
if (len > 1)
1529+
ret = tasdevice_dev_bulk_write(priv, chn, reg,
1530+
&src[6], len);
1531+
else
1532+
ret = tasdevice_dev_write(priv, chn, reg, src[6]);
1533+
} else {
1534+
struct acoustic_data *p = &priv->acou_data;
1535+
1536+
memcpy(p, src, 6);
1537+
if (len > 1) {
1538+
ret = tasdevice_dev_bulk_read(priv, chn, reg,
1539+
p->data, len);
1540+
} else {
1541+
ret = tasdevice_dev_read(priv, chn, reg, &val);
1542+
p->data[0] = val;
1543+
}
1544+
p->len = len + 6;
1545+
}
1546+
1547+
if (ret)
1548+
dev_err(priv->dev, "i2c communication error.\n");
1549+
else
1550+
ret = count;
1551+
exit:
1552+
kfree(src);
1553+
return ret;
1554+
}
1555+
1556+
static const struct file_operations acoustic_ctl_fops = {
1557+
.open = simple_open,
1558+
.read = acoustic_ctl_read,
1559+
.write = acoustic_ctl_write,
1560+
};
1561+
#endif
1562+
14251563
static void tasdevice_fw_ready(const struct firmware *fmw,
14261564
void *context)
14271565
{
14281566
struct tasdevice_priv *tas_priv = context;
1567+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
1568+
struct snd_soc_component *comp = tas_priv->codec;
1569+
struct dentry *debugfs_root = comp->debugfs_root;
1570+
char *acoustic_debugfs_node;
1571+
#endif
14291572
int ret = 0;
14301573
int i;
14311574

@@ -1499,6 +1642,17 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
14991642

15001643
tasdevice_prmg_load(tas_priv, 0);
15011644
tas_priv->cur_prog = 0;
1645+
1646+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
1647+
if (tas_priv->name_prefix)
1648+
acoustic_debugfs_node = devm_kasprintf(tas_priv->dev,
1649+
GFP_KERNEL, "%s_acoustic_ctl", tas_priv->name_prefix);
1650+
else
1651+
acoustic_debugfs_node = devm_kstrdup(tas_priv->dev,
1652+
"acoustic_ctl", GFP_KERNEL);
1653+
debugfs_create_file(acoustic_debugfs_node, 0644, debugfs_root,
1654+
comp, &acoustic_ctl_fops);
1655+
#endif
15021656
out:
15031657
if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
15041658
/* If DSP FW fail, DSP kcontrol won't be created. */

0 commit comments

Comments
 (0)