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.c190
1 files changed, 142 insertions, 48 deletions
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 0e09d794516f..1539b70881d1 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -30,8 +30,10 @@
#include <sound/tas2781.h>
#include <sound/tas2781-comlib-i2c.h>
#include <sound/tlv.h>
+#include <sound/tas2x20-tlv.h>
#include <sound/tas2563-tlv.h>
#include <sound/tas2781-tlv.h>
+#include <sound/tas5825-tlv.h>
#include <linux/unaligned.h>
#define X2563_CL_STT_VAL(xreg, xval) \
@@ -98,16 +100,32 @@ static const struct bulk_reg_val tas2781_cali_start_reg[] = {
};
static const struct i2c_device_id tasdevice_id[] = {
+ { "tas2020", TAS2020 },
+ { "tas2118", TAS2118 },
+ { "tas2120", TAS2120 },
+ { "tas2320", TAS2320 },
{ "tas2563", TAS2563 },
+ { "tas2570", TAS2570 },
+ { "tas2572", TAS2572 },
{ "tas2781", TAS2781 },
+ { "tas5825", TAS5825 },
+ { "tas5827", TAS5827 },
{}
};
MODULE_DEVICE_TABLE(i2c, tasdevice_id);
#ifdef CONFIG_OF
static const struct of_device_id tasdevice_of_match[] = {
+ { .compatible = "ti,tas2020" },
+ { .compatible = "ti,tas2118" },
+ { .compatible = "ti,tas2120" },
+ { .compatible = "ti,tas2320" },
{ .compatible = "ti,tas2563" },
+ { .compatible = "ti,tas2570" },
+ { .compatible = "ti,tas2572" },
{ .compatible = "ti,tas2781" },
+ { .compatible = "ti,tas5825" },
+ { .compatible = "ti,tas5827" },
{},
};
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
@@ -797,7 +815,7 @@ static int tasdev_nop_get(
return 0;
}
-static int tas2563_digital_gain_get(
+static int tasdevice_digital_gain_get(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -823,15 +841,15 @@ static int tas2563_digital_gain_get(
while (r > 1 + l) {
mid = (l + r) / 2;
- ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
+ ar_mid = get_unaligned_be32(tas_dev->dvc_tlv_table[mid]);
if (target < ar_mid)
r = mid;
else
l = mid;
}
- ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
- ar_r = get_unaligned_be32(tas2563_dvc_table[r]);
+ ar_l = get_unaligned_be32(tas_dev->dvc_tlv_table[l]);
+ ar_r = get_unaligned_be32(tas_dev->dvc_tlv_table[r]);
/* find out the member same as or closer to the current volume */
ucontrol->value.integer.value[0] =
@@ -841,7 +859,7 @@ out:
return 0;
}
-static int tas2563_digital_gain_put(
+static int tasdevice_digital_gain_put(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -867,7 +885,7 @@ static int tas2563_digital_gain_put(
}
volrd = get_unaligned_be32(&data[0]);
- volwr = get_unaligned_be32(tas2563_dvc_table[vol]);
+ volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]);
if (volrd == volwr) {
rc = 0;
@@ -876,7 +894,7 @@ static int tas2563_digital_gain_put(
for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
- (unsigned char *)tas2563_dvc_table[vol], 4);
+ (unsigned char *)tas_dev->dvc_tlv_table[vol], 4);
if (ret) {
dev_err(tas_dev->dev,
"%s, set digital vol error in dev %d\n",
@@ -892,11 +910,6 @@ out:
return rc;
}
-static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
- SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
- tasdev_force_fwload_get, tasdev_force_fwload_put),
-};
-
static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0,
tasdev_nop_get, tasdev_calib_stop_put),
@@ -907,6 +920,16 @@ static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
SND_SOC_BYTES_EXT("Amp XMA2 Data", 6, tasdev_XMA2_data_get, NULL),
};
+static const struct snd_kcontrol_new tas2x20_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2X20_AMP_LEVEL,
+ 0, 0, 42, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2x20_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2X20_DVC_LEVEL,
+ 0, 0, ARRAY_SIZE(tas2x20_dvc_table) - 1, 0,
+ tasdevice_digital_gain_get, tasdevice_digital_gain_put,
+ tas2x20_dvc_tlv),
+};
+
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
@@ -916,6 +939,15 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
tas2781_digital_putvol, tas2781_dvc_tlv),
};
+static const struct snd_kcontrol_new tas5825_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
+ 0, 0, 31, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
+ 0, 0, 254, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_dvc_tlv),
+};
+
static const struct snd_kcontrol_new tas2781_cali_controls[] = {
SND_SOC_BYTES_EXT("Amp Latch Data", 3, tas2781_latch_reg_get, NULL),
};
@@ -923,7 +955,7 @@ static const struct snd_kcontrol_new tas2781_cali_controls[] = {
static const struct snd_kcontrol_new tas2563_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0,
0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
- tas2563_digital_gain_get, tas2563_digital_gain_put,
+ tasdevice_digital_gain_get, tasdevice_digital_gain_put,
tas2563_dvc_tlv),
};
@@ -968,8 +1000,8 @@ static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol,
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
- uinfo->value.integer.min = TAS2563;
- uinfo->value.integer.max = TAS2781;
+ uinfo->value.integer.min = TAS2020;
+ uinfo->value.integer.max = TAS_OTHERS;
return 0;
}
@@ -1168,9 +1200,9 @@ static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol,
static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
{
struct snd_kcontrol_new *dsp_ctrls;
- char *active_dev_num, *chip_id;
+ char *active_dev_num, *chip_id, *fw_load;
char *conf_name, *prog_name;
- int nr_controls = 4;
+ int nr_controls = 5;
int mix_index = 0;
/* Alloc kcontrol via devm_kzalloc, which don't manually
@@ -1228,6 +1260,19 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
dsp_ctrls[mix_index].get = tasdevice_get_chip_id;
mix_index++;
+ fw_load = devm_kstrdup(tas_priv->dev, "Speaker Force Firmware Load",
+ GFP_KERNEL);
+ if (!fw_load)
+ return -ENOMEM;
+
+ dsp_ctrls[mix_index].name = fw_load;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = snd_soc_info_bool_ext;
+ dsp_ctrls[mix_index].put = tasdev_force_fwload_put;
+ dsp_ctrls[mix_index].get = tasdev_force_fwload_get;
+ dsp_ctrls[mix_index].private_value = 0UL;
+ mix_index++;
+
return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
nr_controls < mix_index ? nr_controls : mix_index);
}
@@ -1587,6 +1632,16 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
* failing to load DSP firmware is NOT an error.
*/
tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
+ /* There is no DSP firmware required for TAS2118/2X20/257X. */
+ switch (tas_priv->chip_id) {
+ case TAS2020:
+ case TAS2118:
+ case TAS2120:
+ case TAS2320:
+ case TAS2570:
+ case TAS2572:
+ goto out;
+ }
if (tas_priv->name_prefix)
scnprintf(tas_priv->coef_binaryname, 64, "%s-%s_coef.bin",
tas_priv->name_prefix, tas_priv->dev_name);
@@ -1608,39 +1663,48 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
dev_err(tas_priv->dev, "dsp controls error\n");
goto out;
}
-
- ret = tasdevice_create_cali_ctrls(tas_priv);
- if (ret) {
- dev_err(tas_priv->dev, "cali controls error\n");
- goto out;
- }
-
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
- /* If calibrated data occurs error, dsp will still works with default
- * calibrated data inside algo.
- */
- for (i = 0; i < tas_priv->ndev; i++) {
- if (tas_priv->name_prefix)
- scnprintf(tas_priv->cal_binaryname[i], 64,
- "%s-%s_cal_0x%02x.bin", tas_priv->name_prefix,
- tas_priv->dev_name,
- tas_priv->tasdevice[i].dev_addr);
- else
- scnprintf(tas_priv->cal_binaryname[i], 64,
- "%s_cal_0x%02x.bin", tas_priv->dev_name,
- tas_priv->tasdevice[i].dev_addr);
- ret = tas2781_load_calibration(tas_priv,
- tas_priv->cal_binaryname[i], i);
- if (ret != 0)
- dev_err(tas_priv->dev,
- "%s: load %s error, default will effect\n",
- __func__, tas_priv->cal_binaryname[i]);
+ /* There is no calibration required for TAS5825/TAS5827. */
+ if (tas_priv->chip_id < TAS5825) {
+ ret = tasdevice_create_cali_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "cali controls error\n");
+ goto out;
+ }
+ /* If calibrated data occurs error, dsp will still works
+ * with default calibrated data inside algo.
+ */
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s-%s_cal_0x%02x.bin",
+ tas_priv->name_prefix,
+ tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
+ else
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s_cal_0x%02x.bin",
+ tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
+ ret = tas2781_load_calibration(tas_priv,
+ tas_priv->cal_binaryname[i], i);
+ if (ret != 0)
+ dev_err(tas_priv->dev,
+ "%s: load %s error, keep default.\n",
+ __func__, tas_priv->cal_binaryname[i]);
+ }
}
tasdevice_prmg_load(tas_priv, 0);
tas_priv->cur_prog = 0;
+ /* Init common setting for different audio profiles */
+ if (tas_priv->rcabin.init_profile_id >= 0)
+ tasdevice_select_cfg_blk(tas_priv,
+ tas_priv->rcabin.init_profile_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
if (tas_priv->name_prefix)
acoustic_debugfs_node = devm_kasprintf(tas_priv->dev,
@@ -1653,8 +1717,14 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
#endif
out:
if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
- /* If DSP FW fail, DSP kcontrol won't be created. */
- tasdevice_dsp_remove(tas_priv);
+ switch (tas_priv->chip_id) {
+ case TAS2563:
+ case TAS2781:
+ case TAS5825:
+ case TAS5827:
+ /* If DSP FW fail, DSP kcontrol won't be created. */
+ tasdevice_dsp_remove(tas_priv);
+ }
}
mutex_unlock(&tas_priv->codec_lock);
release_firmware(fmw);
@@ -1798,13 +1868,30 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec)
int rc;
switch (tas_priv->chip_id) {
+ case TAS2020:
+ case TAS2118:
+ case TAS2120:
+ case TAS2320:
+ case TAS2570:
+ case TAS2572:
+ p = (struct snd_kcontrol_new *)tas2x20_snd_controls;
+ size = ARRAY_SIZE(tas2x20_snd_controls);
+ tas_priv->dvc_tlv_table = tas2x20_dvc_table;
+ break;
case TAS2781:
p = (struct snd_kcontrol_new *)tas2781_snd_controls;
size = ARRAY_SIZE(tas2781_snd_controls);
break;
+ case TAS5825:
+ case TAS5827:
+ p = (struct snd_kcontrol_new *)tas5825_snd_controls;
+ size = ARRAY_SIZE(tas5825_snd_controls);
+ break;
default:
p = (struct snd_kcontrol_new *)tas2563_snd_controls;
size = ARRAY_SIZE(tas2563_snd_controls);
+ tas_priv->dvc_tlv_table = tas2563_dvc_table;
+ break;
}
rc = snd_soc_add_component_controls(codec, p, size);
@@ -1844,8 +1931,6 @@ static const struct snd_soc_component_driver
soc_codec_driver_tasdevice = {
.probe = tasdevice_codec_probe,
.remove = tasdevice_codec_remove,
- .controls = tasdevice_snd_controls,
- .num_controls = ARRAY_SIZE(tasdevice_snd_controls),
.dapm_widgets = tasdevice_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
.dapm_routes = tasdevice_audio_map,
@@ -1961,7 +2046,16 @@ static void tasdevice_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_ACPI
static const struct acpi_device_id tasdevice_acpi_match[] = {
- { "TAS2781", TAS2781 },
+ { "TXNW2020", TAS2020 },
+ { "TXNW2118", TAS2118 },
+ { "TXNW2120", TAS2120 },
+ { "TXNW2320", TAS2320 },
+ { "TXNW2563", TAS2563 },
+ { "TXNW2570", TAS2570 },
+ { "TXNW2572", TAS2572 },
+ { "TXNW2781", TAS2781 },
+ { "TXNW5825", TAS5825 },
+ { "TXNW5827", TAS5827 },
{},
};