summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/tas2781-fmwlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/tas2781-fmwlib.c')
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index c969eb38704e..a1d86bd309f4 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;
@@ -2462,6 +2550,9 @@ static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
int k = i * (cali_data->cali_dat_sz_per_dev + 1);
int rc;
+ if (!data || !cali_data->total_sz)
+ return;
+
if (data[k] != i) {
dev_err(priv->dev, "%s: no cal-data for dev %d from usr-spc\n",
__func__, i);
@@ -2469,6 +2560,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);