summaryrefslogtreecommitdiff
path: root/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/hda/codecs/side-codecs/tas2781_hda_i2c.c')
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_i2c.c103
1 files changed, 60 insertions, 43 deletions
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index 45ac5e41bd4f..4dea442d8c30 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -26,6 +26,7 @@
#include <sound/tlv.h>
#include <sound/tas2770-tlv.h>
#include <sound/tas2781-tlv.h>
+#include <sound/tas5825-tlv.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
@@ -50,6 +51,7 @@ enum device_chip_id {
HDA_TAS2563,
HDA_TAS2770,
HDA_TAS2781,
+ HDA_TAS5825,
HDA_OTHERS
};
@@ -156,16 +158,16 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
pm_runtime_get_sync(dev);
- mutex_lock(&tas_hda->priv->codec_lock);
- tasdevice_tuning_switch(tas_hda->priv, 0);
- tas_hda->priv->playback_started = true;
- mutex_unlock(&tas_hda->priv->codec_lock);
+ scoped_guard(mutex, &tas_hda->priv->codec_lock) {
+ tasdevice_tuning_switch(tas_hda->priv, 0);
+ tas_hda->priv->playback_started = true;
+ }
break;
case HDA_GEN_PCM_ACT_CLOSE:
- mutex_lock(&tas_hda->priv->codec_lock);
- tasdevice_tuning_switch(tas_hda->priv, 1);
- tas_hda->priv->playback_started = false;
- mutex_unlock(&tas_hda->priv->codec_lock);
+ scoped_guard(mutex, &tas_hda->priv->codec_lock) {
+ tasdevice_tuning_switch(tas_hda->priv, 1);
+ tas_hda->priv->playback_started = false;
+ }
pm_runtime_put_autosuspend(dev);
break;
@@ -182,15 +184,13 @@ static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
int ret;
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
- mutex_unlock(&tas_priv->codec_lock);
-
return ret;
}
@@ -200,19 +200,14 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- int ret;
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
/* The check of the given value is in tasdevice_amp_putvol. */
- ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
-
- mutex_unlock(&tas_priv->codec_lock);
-
- return ret;
+ return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
}
static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
@@ -220,14 +215,12 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
__func__, kcontrol->id.name, tas_priv->force_fwload_status);
- mutex_unlock(&tas_priv->codec_lock);
-
return 0;
}
@@ -237,7 +230,7 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
bool change, val = (bool)ucontrol->value.integer.value[0];
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
__func__, kcontrol->id.name,
@@ -250,8 +243,6 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
tas_priv->force_fwload_status = val;
}
- mutex_unlock(&tas_priv->codec_lock);
-
return change;
}
@@ -265,9 +256,20 @@ static const struct snd_kcontrol_new tas2770_snd_controls[] = {
};
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
- ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
- tas2781_amp_putvol, amp_vol_tlv),
+ tas2781_amp_putvol, tas2781_amp_tlv),
+ ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas5825_snd_controls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
+ 0, 0, 31, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_amp_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
+ 0, 0, 254, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_dvc_tlv),
ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
tas2781_force_fwload_get, tas2781_force_fwload_put),
};
@@ -300,20 +302,26 @@ static int tas2563_save_calibration(struct tas2781_hda *h)
{
efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
char *vars[TASDEV_CALIB_N] = {
- "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d"
+ "R0_%d", "R0_Low_%d", "InvR0_%d", "Power_%d", "TLim_%d"
};
efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX];
unsigned long max_size = TAS2563_CAL_DATA_SIZE;
unsigned char var8[TAS2563_CAL_VAR_NAME_MAX];
- struct tasdevice_priv *p = h->hda_priv;
+ struct tasdevice_priv *p = h->priv;
struct calidata *cd = &p->cali_data;
struct cali_reg *r = &cd->cali_reg_array;
unsigned int offset = 0;
unsigned char *data;
+ __be32 bedata;
efi_status_t status;
unsigned int attr;
int ret, i, j, k;
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
+ dev_err(p->dev, "%s: NO EFI FOUND!\n", __func__);
+ return -EINVAL;
+ }
+
cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N;
/* extra byte for each device is the device number */
@@ -327,8 +335,8 @@ static int tas2563_save_calibration(struct tas2781_hda *h)
data[offset] = i;
offset++;
for (j = 0; j < TASDEV_CALIB_N; ++j) {
- ret = snprintf(var8, sizeof(var8), vars[j], i);
-
+ /* EFI name for calibration started with 1, not 0 */
+ ret = snprintf(var8, sizeof(var8), vars[j], i + 1);
if (ret < 0 || ret >= sizeof(var8) - 1) {
dev_err(p->dev, "%s: Read %s failed\n",
__func__, var8);
@@ -351,12 +359,14 @@ static int tas2563_save_calibration(struct tas2781_hda *h)
i, j, status);
return -EINVAL;
}
+ bedata = cpu_to_be32(*(uint32_t *)&data[offset]);
+ memcpy(&data[offset], &bedata, sizeof(bedata));
offset += TAS2563_CAL_DATA_SIZE;
}
}
if (cd->total_sz != offset) {
- dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n",
+ dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) mismatch\n",
__func__, cd->total_sz, offset);
return -EINVAL;
}
@@ -501,6 +511,12 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
ARRAY_SIZE(tas2781_snd_controls));
tasdevice_dspfw_init(context);
break;
+ case HDA_TAS5825:
+ tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
+ &tas5825_snd_controls[0],
+ ARRAY_SIZE(tas5825_snd_controls));
+ tasdevice_dspfw_init(context);
+ break;
case HDA_TAS2563:
tasdevice_dspfw_init(context);
break;
@@ -628,6 +644,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
} else if (strstarts(dev_name(&clt->dev),
"i2c-TXNW2781:00-tas2781-hda.0")) {
device_name = "TXNW2781";
+ hda_priv->hda_chip_id = HDA_TAS2781;
hda_priv->save_calibration = tas2781_save_calibration;
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
} else if (strstr(dev_name(&clt->dev), "INT8866")) {
@@ -639,6 +656,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
hda_priv->hda_chip_id = HDA_TAS2563;
hda_priv->save_calibration = tas2563_save_calibration;
tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
+ } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) {
+ /*
+ * TAS5825, integrated on-chip DSP without
+ * global I2C address and calibration supported.
+ */
+ device_name = "TXNW5825";
+ hda_priv->hda_chip_id = HDA_TAS5825;
} else {
return -ENODEV;
}
@@ -684,7 +708,7 @@ static int tas2781_runtime_suspend(struct device *dev)
dev_dbg(tas_hda->dev, "Runtime Suspend\n");
- mutex_lock(&tas_hda->priv->codec_lock);
+ guard(mutex)(&tas_hda->priv->codec_lock);
/* The driver powers up the amplifiers at module load time.
* Stop the playback if it's unused.
@@ -694,8 +718,6 @@ static int tas2781_runtime_suspend(struct device *dev)
tas_hda->priv->playback_started = false;
}
- mutex_unlock(&tas_hda->priv->codec_lock);
-
return 0;
}
@@ -705,12 +727,10 @@ static int tas2781_runtime_resume(struct device *dev)
dev_dbg(tas_hda->dev, "Runtime Resume\n");
- mutex_lock(&tas_hda->priv->codec_lock);
+ guard(mutex)(&tas_hda->priv->codec_lock);
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
- mutex_unlock(&tas_hda->priv->codec_lock);
-
return 0;
}
@@ -720,14 +740,12 @@ static int tas2781_system_suspend(struct device *dev)
dev_dbg(tas_hda->priv->dev, "System Suspend\n");
- mutex_lock(&tas_hda->priv->codec_lock);
+ guard(mutex)(&tas_hda->priv->codec_lock);
/* Shutdown chip before system suspend */
if (tas_hda->priv->playback_started)
tasdevice_tuning_switch(tas_hda->priv, 1);
- mutex_unlock(&tas_hda->priv->codec_lock);
-
/*
* Reset GPIO may be shared, so cannot reset here.
* However beyond this point, amps may be powered down.
@@ -742,7 +760,7 @@ static int tas2781_system_resume(struct device *dev)
dev_dbg(tas_hda->priv->dev, "System Resume\n");
- mutex_lock(&tas_hda->priv->codec_lock);
+ guard(mutex)(&tas_hda->priv->codec_lock);
for (i = 0; i < tas_hda->priv->ndev; i++) {
tas_hda->priv->tasdevice[i].cur_book = -1;
@@ -755,8 +773,6 @@ static int tas2781_system_resume(struct device *dev)
if (tas_hda->priv->playback_started)
tasdevice_tuning_switch(tas_hda->priv, 0);
- mutex_unlock(&tas_hda->priv->codec_lock);
-
return 0;
}
@@ -775,6 +791,7 @@ static const struct acpi_device_id tas2781_acpi_hda_match[] = {
{"TIAS2781", 0 },
{"TXNW2770", 0 },
{"TXNW2781", 0 },
+ {"TXNW5825", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);