summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/tas2781-i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/tas2781-i2c.c')
-rw-r--r--sound/soc/codecs/tas2781-i2c.c288
1 files changed, 189 insertions, 99 deletions
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 728bf78ae71f..b950914b7d48 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -2,7 +2,7 @@
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
-// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2025 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563/TAS2781 driver implements a flexible and configurable
@@ -349,13 +349,31 @@ static int calib_data_get(struct tasdevice_priv *tas_priv, int reg,
return rc;
}
+static int partial_cali_data_update(int *reg, int j)
+{
+ switch (tas2781_cali_start_reg[j].reg) {
+ case 0:
+ return reg[0];
+ case TAS2781_PRM_PLT_FLAG_REG:
+ return reg[1];
+ case TAS2781_PRM_SINEGAIN_REG:
+ return reg[2];
+ case TAS2781_PRM_SINEGAIN2_REG:
+ return reg[3];
+ default:
+ return 0;
+ }
+}
+
static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
int *reg, unsigned char *dat)
{
struct tasdevice *tasdev = tas_priv->tasdevice;
struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+ struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;
const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
- int j;
+ unsigned char val[4];
+ int j, r;
if (p == NULL)
return;
@@ -370,30 +388,23 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
tasdevice_dev_read(tas_priv, i, p[j].reg,
(int *)&p[j].val[0]);
} else {
- switch (tas2781_cali_start_reg[j].reg) {
- case 0: {
- if (!reg[0])
- continue;
- p[j].reg = reg[0];
+ if (!tas_priv->dspbin_typ) {
+ r = partial_cali_data_update(reg, j);
+ if (r)
+ p[j].reg = r;
}
- break;
- case TAS2781_PRM_PLT_FLAG_REG:
- p[j].reg = reg[1];
- break;
- case TAS2781_PRM_SINEGAIN_REG:
- p[j].reg = reg[2];
- break;
- case TAS2781_PRM_SINEGAIN2_REG:
- p[j].reg = reg[3];
- break;
- }
- tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
- p[j].val, 4);
+
+ if (p[j].reg)
+ tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
+ p[j].val, 4);
}
}
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA)
+ tasdevice_dev_bulk_read(tas_priv, i, t->reg, t->val, 4);
+
/* Update the setting for calibration */
- for (j = 0; j < sum - 2; j++) {
+ for (j = 0; j < sum - 4; j++) {
if (p[j].val_len == 1) {
if (p[j].is_locked)
tasdevice_dev_write(tas_priv, i,
@@ -401,17 +412,33 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
TAS2781_TEST_PAGE_UNLOCK);
tasdevice_dev_write(tas_priv, i, p[j].reg,
tas2781_cali_start_reg[j].val[0]);
- } else {
- if (!p[j].reg)
- continue;
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
- (unsigned char *)
- tas2781_cali_start_reg[j].val, 4);
}
}
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, &dat[1], 4);
- tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg, &dat[5], 4);
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
+ val[0] = 0x00;
+ val[1] = 0x00;
+ val[2] = 0x21;
+ val[3] = 0x8e;
+ } else {
+ val[0] = tas2781_cali_start_reg[j].val[0];
+ val[1] = tas2781_cali_start_reg[j].val[1];
+ val[2] = tas2781_cali_start_reg[j].val[2];
+ val[3] = tas2781_cali_start_reg[j].val[3];
+ }
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, val, 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg,
+ (unsigned char *)tas2781_cali_start_reg[j + 1].val, 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 2].reg, &dat[1], 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 3].reg, &dat[5], 4);
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
+ val[0] = 0x00;
+ val[1] = 0x00;
+ val[2] = 0x2a;
+ val[3] = 0x0b;
+
+ tasdevice_dev_bulk_read(tas_priv, i, t->reg, val, 4);
+ }
}
static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
@@ -452,14 +479,15 @@ static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv)
+static void tas2781_calib_stop_put(struct tasdevice_priv *priv)
{
const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
int i, j;
- for (i = 0; i < tas_priv->ndev; i++) {
- struct tasdevice *tasdev = tas_priv->tasdevice;
+ for (i = 0; i < priv->ndev; i++) {
+ struct tasdevice *tasdev = priv->tasdevice;
struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+ struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;
if (p == NULL)
continue;
@@ -467,18 +495,21 @@ static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv)
for (j = 0; j < sum; j++) {
if (p[j].val_len == 1) {
if (p[j].is_locked)
- tasdevice_dev_write(tas_priv, i,
+ tasdevice_dev_write(priv, i,
TAS2781_TEST_UNLOCK_REG,
TAS2781_TEST_PAGE_UNLOCK);
- tasdevice_dev_write(tas_priv, i, p[j].reg,
+ tasdevice_dev_write(priv, i, p[j].reg,
p[j].val[0]);
} else {
if (!p[j].reg)
continue;
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ tasdevice_dev_bulk_write(priv, i, p[j].reg,
p[j].val, 4);
}
}
+
+ if (priv->dspbin_typ == TASDEV_ALPHA)
+ tasdevice_dev_bulk_write(priv, i, t->reg, t->val, 4);
}
}
@@ -489,14 +520,11 @@ static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
- int rc = 1;
int i, j;
guard(mutex)(&tas_priv->codec_lock);
- if (tas_priv->chip_id != TAS2563) {
- rc = -1;
- goto out;
- }
+ if (tas_priv->chip_id != TAS2563)
+ return -1;
for (i = 0; i < tas_priv->ndev; i++) {
struct tasdevice *tasdev = tas_priv->tasdevice;
@@ -523,8 +551,8 @@ static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
q[j].val, 4);
}
}
-out:
- return rc;
+
+ return 1;
}
static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv)
@@ -576,7 +604,7 @@ static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
struct cali_reg *p = &cali_data->cali_reg_array;
unsigned char *src = ucontrol->value.bytes.data;
unsigned char *dst = cali_data->data;
- int rc = 1, i = 0;
+ int i = 0;
int j;
guard(mutex)(&priv->codec_lock);
@@ -593,19 +621,23 @@ static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
i += 2;
priv->is_user_space_calidata = true;
- p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
+ if (priv->dspbin_typ == TASDEV_BASIC) {
+ p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ } else {
+ i += 15;
+ }
memcpy(dst, &src[i], cali_data->total_sz);
- return rc;
+ return 1;
}
static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol,
@@ -649,12 +681,19 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
- unsigned int reg;
+ unsigned int reg = TAS2781_RUNTIME_RE_REG_TF;
+
+ if (tas_priv->chip_id == TAS2781) {
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
- if (tas_priv->chip_id == TAS2781)
reg = TAS2781_RUNTIME_RE_REG_TF;
- else
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->tf_reg[0], p->tf_reg[1],
+ p->tf_reg[2]);
+ } else {
reg = TAS2563_RUNTIME_RE_REG_TF;
+ }
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
@@ -669,12 +708,19 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
- unsigned int reg;
+ unsigned int reg = TAS2781_RUNTIME_RE_REG;
- if (tas_priv->chip_id == TAS2781)
- reg = TAS2781_RUNTIME_RE_REG;
- else
+ if (tas_priv->chip_id == TAS2781) {
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
+
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->r0_reg[0], p->r0_reg[1],
+ p->r0_reg[2]);
+ } else {
reg = TAS2563_RUNTIME_RE_REG;
+ }
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -708,11 +754,16 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A1_REG;
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->a1_reg[0], p->a1_reg[1], p->a1_reg[2]);
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -723,11 +774,16 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A2_REG;
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->a2_reg[0], p->a2_reg[1], p->a2_reg[2]);
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -1115,25 +1171,21 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
char *conf_name, *prog_name;
int nr_controls = 4;
int mix_index = 0;
- int ret;
/* Alloc kcontrol via devm_kzalloc, which don't manually
* free the kcontrol
*/
dsp_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
sizeof(dsp_ctrls[0]), GFP_KERNEL);
- if (!dsp_ctrls) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!dsp_ctrls)
+ return -ENOMEM;
/* Create mixer items for selecting the active Program and Config */
prog_name = devm_kstrdup(tas_priv->dev, "Speaker Program Id",
GFP_KERNEL);
- if (!prog_name) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!prog_name)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = prog_name;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_programs;
@@ -1143,10 +1195,9 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
conf_name = devm_kstrdup(tas_priv->dev, "Speaker Config Id",
GFP_KERNEL);
- if (!conf_name) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!conf_name)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = conf_name;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_configurations;
@@ -1156,10 +1207,9 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
active_dev_num = devm_kstrdup(tas_priv->dev, "Activate Tasdevice Num",
GFP_KERNEL);
- if (!active_dev_num) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!active_dev_num)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = active_dev_num;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_active_num;
@@ -1168,27 +1218,64 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
mix_index++;
chip_id = devm_kstrdup(tas_priv->dev, "Tasdevice Chip Id", GFP_KERNEL);
- if (!chip_id) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!chip_id)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = chip_id;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_chip_id;
dsp_ctrls[mix_index].get = tasdevice_get_chip_id;
mix_index++;
- ret = snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
+ return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
nr_controls < mix_index ? nr_controls : mix_index);
+}
-out:
- return ret;
+static void cali_reg_update(struct bulk_reg_val *p,
+ struct fct_param_address *t)
+{
+ const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
+ int reg, j;
+
+ for (j = 0; j < sum; j++) {
+ switch (tas2781_cali_start_reg[j].reg) {
+ case 0:
+ reg = TASDEVICE_REG(t->thr[0], t->thr[1], t->thr[2]);
+ break;
+ case TAS2781_PRM_PLT_FLAG_REG:
+ reg = TASDEVICE_REG(t->plt_flg[0], t->plt_flg[1],
+ t->plt_flg[2]);
+ break;
+ case TAS2781_PRM_SINEGAIN_REG:
+ reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
+ t->sin_gn[2]);
+ break;
+ case TAS2781_PRM_SINEGAIN2_REG:
+ reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
+ t->sin_gn[2]);
+ break;
+ default:
+ reg = 0;
+ break;
+ }
+ if (reg)
+ p[j].reg = reg;
+ }
+}
+
+static void alpa_cali_update(struct bulk_reg_val *p,
+ struct fct_param_address *t)
+{
+ p->is_locked = false;
+ p->reg = TASDEVICE_REG(t->thr2[0], t->thr2[1], t->thr2[2]);
+ p->val_len = 4;
}
static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
{
struct calidata *cali_data = &priv->cali_data;
struct tasdevice *tasdev = priv->tasdevice;
+ struct tasdevice_fw *fmw = priv->fmw;
struct soc_bytes_ext *ext_cali_data;
struct snd_kcontrol_new *cali_ctrls;
unsigned int nctrls;
@@ -1204,14 +1291,25 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
}
if (priv->chip_id == TAS2781) {
+ struct fct_param_address *t = &(fmw->fct_par_addr);
+
cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls;
nctrls = ARRAY_SIZE(tas2781_cali_controls);
for (i = 0; i < priv->ndev; i++) {
- tasdev[i].cali_data_backup =
+ struct bulk_reg_val *p;
+
+ p = tasdev[i].cali_data_backup =
kmemdup(tas2781_cali_start_reg,
sizeof(tas2781_cali_start_reg), GFP_KERNEL);
if (!tasdev[i].cali_data_backup)
return -ENOMEM;
+ if (priv->dspbin_typ) {
+ cali_reg_update(p, t);
+ if (priv->dspbin_typ == TASDEV_ALPHA) {
+ p = &tasdev[i].alp_cali_bckp;
+ alpa_cali_update(p, t);
+ }
+ }
}
} else {
cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls;
@@ -1273,8 +1371,6 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
(cali_data->cali_dat_sz_per_dev + 1) + 1 + 15 + 1;
priv->cali_data.total_sz = priv->ndev *
(cali_data->cali_dat_sz_per_dev + 1);
- priv->cali_data.data = devm_kzalloc(priv->dev,
- ext_cali_data->max, GFP_KERNEL);
cali_ctrls[i].name = cali_name;
cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
cali_ctrls[i].info = snd_soc_bytes_info_ext;
@@ -1469,7 +1565,6 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
unsigned int slot_width;
unsigned int fsrate;
int bclk_rate;
- int rc = 0;
fsrate = params_rate(params);
switch (fsrate) {
@@ -1479,8 +1574,7 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n",
__func__, fsrate);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
slot_width = params_width(params);
@@ -1493,20 +1587,17 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n",
__func__, slot_width);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
bclk_rate = snd_soc_params_to_bclk(params);
if (bclk_rate < 0) {
dev_err(tas_priv->dev, "%s: incorrect bclk rate = %d\n",
__func__, bclk_rate);
- rc = bclk_rate;
- goto out;
+ return bclk_rate;
}
-out:
- return rc;
+ return 0;
}
static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -1663,7 +1754,6 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
static int tasdevice_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_match_id(tasdevice_id, i2c);
const struct acpi_device_id *acpi_id;
struct tasdevice_priv *tas_priv;
int ret;
@@ -1685,7 +1775,7 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
tas_priv->chip_id = acpi_id->driver_data;
tas_priv->isacpi = true;
} else {
- tas_priv->chip_id = id ? id->driver_data : 0;
+ tas_priv->chip_id = (uintptr_t)i2c_get_match_data(i2c);
tas_priv->isacpi = false;
}