mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:24:45 +01:00
ALSA: hda/tas2781: A workaround solution to lower-vol issue among lower calibrated-impedance micro-speaker on TAS2781
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> Tested-by: Matthew Schwartz <matthew.schwartz@linux.dev> Link: https://patch.msgid.link/20260227144641.1243-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
068641bc9d
commit
05ac3846ff
3 changed files with 98 additions and 12 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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")) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue