From: Matthew Schwartz <matthew.schwartz@linux.dev>
To: Shenghao Ding <shenghao-ding@ti.com>, tiwai@suse.de
Cc: broonie@kernel.org, andriy.shevchenko@linux.intel.com,
linux-kernel@vger.kernel.org, baojun.xu@ti.com,
Baojun.Xu@fpt.com, 13564923607@139.com, 13916275206@139.com,
lkml@antheas.dev
Subject: Re: [PATCH v1] ALSA: hda/tas2781: A workaround solution to lower-vol issue among lower calibrated-impedance micro-speaker on TAS2781
Date: Fri, 27 Feb 2026 13:00:51 -0800 [thread overview]
Message-ID: <c1f38bbb-c6e3-4802-bb57-3f4f64211e12@linux.dev> (raw)
In-Reply-To: <20260227144641.1243-1-shenghao-ding@ti.com>
On 2/27/26 6:46 AM, Shenghao Ding wrote:
> On TAS2781, if the Speaker calibrated impedance is lower than default
> value hard-coded inside the TAS2781, it will cuase vol lower than
> normal. In order to fix this issue, the parameter of SineGainI need
> updating.
>
> Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
Fixes the audio dropout issue from https://lore.kernel.org/all/0ba100d0-9b6f-4a3b-bffa-61abe1b46cd5@linux.dev/
without a quirk to skip calibration on ROG Xbox Ally X. I also tested on ROG Xbox Ally, but I never experienced
this specific issue on that device.
Tested-by: Matthew Schwartz <matthew.schwartz@linux.dev>
>
> ---
> v1:
> - Add tas2781_cali_preproc() to check whether the calibrated-impedance is lower than the default value. If so, update the SineGainI.
> - Specify the TAS2781 chipid for cliabrated data preprocessing.
> - Revert b7e26c8bdae7 ("ALSA: hda/tas2781: Skip UEFI calibration on ASUS ROG Xbox Ally X") in tas2781.
> ---
> include/sound/tas2781.h | 1 +
> .../hda/codecs/side-codecs/tas2781_hda_i2c.c | 15 +--
> sound/soc/codecs/tas2781-fmwlib.c | 94 +++++++++++++++++++
> 3 files changed, 98 insertions(+), 12 deletions(-)
>
> diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
> index 7c03bdc951bb..e847cf51878c 100644
> --- a/include/sound/tas2781.h
> +++ b/include/sound/tas2781.h
> @@ -151,6 +151,7 @@ struct tasdevice {
> struct bulk_reg_val *cali_data_backup;
> struct bulk_reg_val alp_cali_bckp;
> struct tasdevice_fw *cali_data_fmw;
> + void *cali_specific;
> unsigned int dev_addr;
> unsigned int err_code;
> unsigned char cur_book;
> diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
> index 74c3cf1e45e1..67240ce184e1 100644
> --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
> +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
> @@ -60,7 +60,6 @@ struct tas2781_hda_i2c_priv {
> int (*save_calibration)(struct tas2781_hda *h);
>
> int hda_chip_id;
> - bool skip_calibration;
> };
>
> static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
> @@ -479,8 +478,7 @@ static void tasdevice_dspfw_init(void *context)
> /* If calibrated data occurs error, dsp will still works with default
> * calibrated data inside algo.
> */
> - if (!hda_priv->skip_calibration)
> - hda_priv->save_calibration(tas_hda);
> + hda_priv->save_calibration(tas_hda);
> }
>
> static void tasdev_fw_ready(const struct firmware *fmw, void *context)
> @@ -535,7 +533,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
> void *master_data)
> {
> struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
> - struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
> struct hda_component_parent *parent = master_data;
> struct hda_component *comp;
> struct hda_codec *codec;
> @@ -564,14 +561,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
> break;
> }
>
> - /*
> - * Using ASUS ROG Xbox Ally X (RC73XA) UEFI calibration data
> - * causes audio dropouts during playback, use fallback data
> - * from DSP firmware as a workaround.
> - */
> - if (codec->core.subsystem_id == 0x10431384)
> - hda_priv->skip_calibration = true;
> -
> guard(pm_runtime_active_auto)(dev);
>
> comp->dev = dev;
> @@ -643,6 +632,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
> */
> device_name = "TIAS2781";
> hda_priv->hda_chip_id = HDA_TAS2781;
> + tas_hda->priv->chip_id = TAS2781;
> hda_priv->save_calibration = tas2781_save_calibration;
> tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
> } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) {
> @@ -656,6 +646,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
> "i2c-TXNW2781:00-tas2781-hda.0")) {
> device_name = "TXNW2781";
> hda_priv->hda_chip_id = HDA_TAS2781;
> + tas_hda->priv->chip_id = TAS2781;
> hda_priv->save_calibration = tas2781_save_calibration;
> tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
> } else if (strstr(dev_name(&clt->dev), "INT8866")) {
> diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
> index c969eb38704e..5798d518d94c 100644
> --- a/sound/soc/codecs/tas2781-fmwlib.c
> +++ b/sound/soc/codecs/tas2781-fmwlib.c
> @@ -32,6 +32,10 @@
> #define TAS2781_YRAM1_PAGE 42
> #define TAS2781_YRAM1_START_REG 88
>
> +#define TAS2781_PG_REG TASDEVICE_REG(0x00, 0x00, 0x7c)
> +#define TAS2781_PG_1_0 0xA0
> +#define TAS2781_PG_2_0 0xA8
> +
> #define TAS2781_YRAM2_START_PAGE 43
> #define TAS2781_YRAM2_END_PAGE 49
> #define TAS2781_YRAM2_START_REG 8
> @@ -98,6 +102,12 @@ struct blktyp_devidx_map {
> unsigned char dev_idx;
> };
>
> +struct tas2781_cali_specific {
> + unsigned char sin_gni[4];
> + int sin_gni_reg;
> + bool is_sin_gn_flush;
> +};
> +
> static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
> 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
> };
> @@ -2454,6 +2464,84 @@ static int tasdevice_load_data(struct tasdevice_priv *tas_priv,
> return ret;
> }
>
> +static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
> +{
> + struct tas2781_cali_specific *spec = priv->tasdevice[i].cali_specific;
> + struct calidata *cali_data = &priv->cali_data;
> + struct cali_reg *p = &cali_data->cali_reg_array;
> + unsigned char *data = cali_data->data;
> + int rc;
> +
> + /*
> + * On TAS2781, if the Speaker calibrated impedance is lower than
> + * default value hard-coded inside the TAS2781, it will cuase vol
> + * lower than normal. In order to fix this issue, the parameter of
> + * SineGainI need updating.
> + */
> + if (spec == NULL) {
> + int k = i * (cali_data->cali_dat_sz_per_dev + 1);
> + int re_org, re_cal, corrected_sin_gn, pg_id;
> + unsigned char r0_deflt[4];
> +
> + spec = devm_kzalloc(priv->dev, sizeof(*spec), GFP_KERNEL);
> + if (spec == NULL)
> + return -ENOMEM;
> + priv->tasdevice[i].cali_specific = spec;
> + rc = tasdevice_dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
> + if (rc < 0) {
> + dev_err(priv->dev, "invalid RE from %d = %d\n", i, rc);
> + return rc;
> + }
> + /*
> + * SineGainI need to be re-calculated, calculate the high 16
> + * bits.
> + */
> + re_org = r0_deflt[0] << 8 | r0_deflt[1];
> + re_cal = data[k + 1] << 8 | data[k + 2];
> + if (re_org > re_cal) {
> + rc = tasdevice_dev_read(priv, i, TAS2781_PG_REG,
> + &pg_id);
> + if (rc < 0) {
> + dev_err(priv->dev, "invalid PG id %d = %d\n",
> + i, rc);
> + return rc;
> + }
> +
> + spec->sin_gni_reg = (pg_id == TAS2781_PG_1_0) ?
> + TASDEVICE_REG(0, 0x1b, 0x34) :
> + TASDEVICE_REG(0, 0x18, 0x1c);
> +
> + rc = tasdevice_dev_bulk_read(priv, i,
> + spec->sin_gni_reg,
> + spec->sin_gni, 4);
> + if (rc < 0) {
> + dev_err(priv->dev, "wrong sinegaini %d = %d\n",
> + i, rc);
> + return rc;
> + }
> + corrected_sin_gn = re_org * ((spec->sin_gni[0] << 8) +
> + spec->sin_gni[1]);
> + corrected_sin_gn /= re_cal;
> + spec->sin_gni[0] = corrected_sin_gn >> 8;
> + spec->sin_gni[1] = corrected_sin_gn & 0xff;
> +
> + spec->is_sin_gn_flush = true;
> + }
> + }
> +
> + if (spec->is_sin_gn_flush) {
> + rc = tasdevice_dev_bulk_write(priv, i, spec->sin_gni_reg,
> + spec->sin_gni, 4);
> + if (rc < 0) {
> + dev_err(priv->dev, "update failed %d = %d\n",
> + i, rc);
> + return rc;
> + }
> + }
> +
> + return 0;
> +}
> +
> static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
> {
> struct calidata *cali_data = &priv->cali_data;
> @@ -2469,6 +2557,12 @@ static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
> }
> k++;
>
> + if (priv->chip_id == TAS2781) {
> + rc = tas2781_cali_preproc(priv, i);
> + if (rc < 0)
> + return;
> + }
> +
> rc = tasdevice_dev_bulk_write(priv, i, p->r0_reg, &(data[k]), 4);
> if (rc < 0) {
> dev_err(priv->dev, "chn %d r0_reg bulk_wr err = %d\n", i, rc);
next prev parent reply other threads:[~2026-02-27 21:01 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-27 14:46 [PATCH v1] ALSA: hda/tas2781: A workaround solution to lower-vol issue among lower calibrated-impedance micro-speaker on TAS2781 Shenghao Ding
2026-02-27 21:00 ` Matthew Schwartz [this message]
2026-02-28 8:28 ` Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c1f38bbb-c6e3-4802-bb57-3f4f64211e12@linux.dev \
--to=matthew.schwartz@linux.dev \
--cc=13564923607@139.com \
--cc=13916275206@139.com \
--cc=Baojun.Xu@fpt.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=baojun.xu@ti.com \
--cc=broonie@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lkml@antheas.dev \
--cc=shenghao-ding@ti.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.