ALSA: hda/tas2781: Create an independent lib to save the shared parts for both SPI and I2C driver

Some common parts, such as struct tas2781_hda{...} and some audio
kcontrols are moved into an independent lib for code cleanup.

Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
Link: https://patch.msgid.link/20250507045813.151-1-shenghao-ding@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Shenghao Ding
2025-05-07 12:58:13 +08:00
committed by Takashi Iwai
parent 845b997761
commit 28a09d9e42
6 changed files with 405 additions and 457 deletions

View File

@@ -180,12 +180,17 @@ config SND_HDA_SCODEC_CS35L56_SPI
Say Y or M here to include CS35L56 amplifier support with
SPI control.
config SND_HDA_SCODEC_TAS2781
tristate
select SND_HDA_GENERIC
config SND_HDA_SCODEC_TAS2781_I2C
tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
depends on I2C
depends on ACPI
depends on EFI
depends on SND_SOC
select SND_HDA_SCODEC_TAS2781
select SND_SOC_TAS2781_COMLIB_I2C
select SND_SOC_TAS2781_FMWLIB
select CRC32
@@ -202,6 +207,8 @@ config SND_HDA_SCODEC_TAS2781_SPI
depends on ACPI
depends on EFI
depends on SND_SOC
select SND_HDA_SCODEC_TAS2781
select SND_SOC_TAS2781_COMLIB
select SND_SOC_TAS2781_FMWLIB
select CRC8
select CRC32

View File

@@ -38,6 +38,7 @@ snd-hda-scodec-cs35l56-y := cs35l56_hda.o
snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o
snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
snd-hda-scodec-component-y := hda_component.o
snd-hda-scodec-tas2781-y := tas2781_hda.o
snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o
@@ -70,6 +71,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o

198
sound/pci/hda/tas2781_hda.c Normal file
View File

@@ -0,0 +1,198 @@
// SPDX-License-Identifier: GPL-2.0
//
// TAS2781 HDA Shared Lib for I2C&SPI driver
//
// Copyright 2025 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
#include <linux/component.h>
#include <linux/crc8.h>
#include <linux/crc32.h>
#include <linux/efi.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#include "tas2781_hda.h"
void tas2781_hda_remove(struct device *dev,
const struct component_ops *ops)
{
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
component_del(tas_hda->dev, ops);
pm_runtime_get_sync(tas_hda->dev);
pm_runtime_disable(tas_hda->dev);
pm_runtime_put_noidle(tas_hda->dev);
tasdevice_remove(tas_hda->priv);
}
EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
int tasdevice_info_config(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_fw->nr_configurations - 1;
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
int profile_id = ucontrol->value.integer.value[0];
int max = tas_priv->rcabin.ncfgs - 1;
int val, ret = 0;
val = clamp(profile_id, 0, max);
guard(mutex)(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
if (tas_priv->rcabin.profile_cfg_id != val) {
tas_priv->rcabin.profile_cfg_id = val;
ret = 1;
}
return ret;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
int tasdevice_program_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->cur_prog;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
kcontrol->id.name, tas_priv->cur_prog);
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
int tasdevice_program_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
int nr_program = ucontrol->value.integer.value[0];
int max = tas_fw->nr_programs - 1;
int val, ret = 0;
val = clamp(nr_program, 0, max);
guard(mutex)(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
kcontrol->id.name, tas_priv->cur_prog, val);
if (tas_priv->cur_prog != val) {
tas_priv->cur_prog = val;
ret = 1;
}
return ret;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
int tasdevice_config_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->cur_conf;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
kcontrol->id.name, tas_priv->cur_conf);
return 0;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
int tasdevice_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
int nr_config = ucontrol->value.integer.value[0];
int max = tas_fw->nr_configurations - 1;
int val, ret = 0;
val = clamp(nr_config, 0, max);
guard(mutex)(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
kcontrol->id.name, tas_priv->cur_conf, val);
if (tas_priv->cur_conf != val) {
tas_priv->cur_conf = val;
ret = 1;
}
return ret;
}
EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
MODULE_DESCRIPTION("TAS2781 HDA Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");

View File

@@ -44,4 +44,35 @@
.private_value = xdata, \
}
struct tas2781_hda {
struct device *dev;
struct tasdevice_priv *priv;
struct snd_kcontrol *dsp_prog_ctl;
struct snd_kcontrol *dsp_conf_ctl;
struct snd_kcontrol *prof_ctl;
enum device_catlog_id catlog_id;
void *hda_priv;
};
void tas2781_hda_remove(struct device *dev,
const struct component_ops *ops);
int tasdevice_info_profile(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uctl);
int tasdevice_info_programs(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uctl);
int tasdevice_info_config(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uctl);
int tasdevice_set_profile_id(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
int tasdevice_get_profile_id(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
int tasdevice_program_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
int tasdevice_program_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
int tasdevice_config_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
int tasdevice_config_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl);
#endif

View File

@@ -51,12 +51,7 @@ static unsigned int cal_regs[TASDEV_CALIB_N] = {
TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM,
};
struct tas2781_hda {
struct device *dev;
struct tasdevice_priv *priv;
struct snd_kcontrol *dsp_prog_ctl;
struct snd_kcontrol *dsp_conf_ctl;
struct snd_kcontrol *prof_ctl;
struct tas2781_hda_i2c_priv {
struct snd_kcontrol *snd_ctls[2];
};
@@ -175,176 +170,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
}
}
static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
return 0;
}
static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
mutex_lock(&tas_priv->codec_lock);
ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
__func__, kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
mutex_unlock(&tas_priv->codec_lock);
return 0;
}
static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
int nr_profile = ucontrol->value.integer.value[0];
int max = tas_priv->rcabin.ncfgs - 1;
int val, ret = 0;
val = clamp(nr_profile, 0, max);
mutex_lock(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
__func__, kcontrol->id.name,
tas_priv->rcabin.profile_cfg_id, val);
if (tas_priv->rcabin.profile_cfg_id != val) {
tas_priv->rcabin.profile_cfg_id = val;
ret = 1;
}
mutex_unlock(&tas_priv->codec_lock);
return ret;
}
static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_fw->nr_programs - 1;
return 0;
}
static int tasdevice_info_config(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_fw->nr_configurations - 1;
return 0;
}
static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
mutex_lock(&tas_priv->codec_lock);
ucontrol->value.integer.value[0] = tas_priv->cur_prog;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
__func__, kcontrol->id.name, tas_priv->cur_prog);
mutex_unlock(&tas_priv->codec_lock);
return 0;
}
static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
int nr_program = ucontrol->value.integer.value[0];
int max = tas_fw->nr_programs - 1;
int val, ret = 0;
val = clamp(nr_program, 0, max);
mutex_lock(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
__func__, kcontrol->id.name, tas_priv->cur_prog, val);
if (tas_priv->cur_prog != val) {
tas_priv->cur_prog = val;
ret = 1;
}
mutex_unlock(&tas_priv->codec_lock);
return ret;
}
static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
mutex_lock(&tas_priv->codec_lock);
ucontrol->value.integer.value[0] = tas_priv->cur_conf;
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
__func__, kcontrol->id.name, tas_priv->cur_conf);
mutex_unlock(&tas_priv->codec_lock);
return 0;
}
static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
struct tasdevice_fw *tas_fw = tas_priv->fmw;
int nr_config = ucontrol->value.integer.value[0];
int max = tas_fw->nr_configurations - 1;
int val, ret = 0;
val = clamp(nr_config, 0, max);
mutex_lock(&tas_priv->codec_lock);
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
__func__, kcontrol->id.name, tas_priv->cur_conf, val);
if (tas_priv->cur_conf != val) {
tas_priv->cur_conf = val;
ret = 1;
}
mutex_unlock(&tas_priv->codec_lock);
return ret;
}
static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -615,13 +440,14 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
{
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
struct hda_codec *codec = tas_hda->priv->codec;
snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--)
snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);
snd_ctl_remove(codec->card, tas_hda->prof_ctl);
}
@@ -630,6 +456,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
{
struct tasdevice_priv *tas_priv = context;
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
struct hda_codec *codec = tas_priv->codec;
int i, ret, spk_id;
@@ -650,9 +477,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
}
for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) {
tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
@@ -805,31 +632,23 @@ static const struct component_ops tas2781_hda_comp_ops = {
.unbind = tas2781_hda_unbind,
};
static void tas2781_hda_remove(struct device *dev)
{
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
component_del(tas_hda->dev, &tas2781_hda_comp_ops);
pm_runtime_get_sync(tas_hda->dev);
pm_runtime_disable(tas_hda->dev);
pm_runtime_put_noidle(tas_hda->dev);
tasdevice_remove(tas_hda->priv);
}
static int tas2781_hda_i2c_probe(struct i2c_client *clt)
{
struct tas2781_hda_i2c_priv *hda_priv;
struct tas2781_hda *tas_hda;
const char *device_name;
int ret;
tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
if (!tas_hda)
return -ENOMEM;
hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);
if (!hda_priv)
return -ENOMEM;
tas_hda->hda_priv = hda_priv;
dev_set_drvdata(&clt->dev, tas_hda);
tas_hda->dev = &clt->dev;
@@ -876,13 +695,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
err:
if (ret)
tas2781_hda_remove(&clt->dev);
tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
return ret;
}
static void tas2781_hda_i2c_remove(struct i2c_client *clt)
{
tas2781_hda_remove(&clt->dev);
tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
}
static int tas2781_runtime_suspend(struct device *dev)
@@ -1010,3 +829,4 @@ MODULE_DESCRIPTION("TAS2781 HDA Driver");
MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");

View File

@@ -49,13 +49,8 @@
#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
#define TAS2781_REG_CLK_CONFIG_RESET 0x19
struct tas2781_hda {
struct tasdevice_priv *priv;
struct acpi_device *dacpi;
struct snd_kcontrol *dsp_prog_ctl;
struct snd_kcontrol *dsp_conf_ctl;
struct tas2781_hda_spi_priv {
struct snd_kcontrol *snd_ctls[3];
struct snd_kcontrol *prof_ctl;
};
static const struct regmap_range_cfg tasdevice_ranges[] = {
@@ -193,8 +188,10 @@ static void tas2781_spi_reset(struct tasdevice_priv *tas_dev)
} else {
ret = tasdevice_dev_write(tas_dev, tas_dev->index,
TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET);
if (ret < 0)
if (ret < 0) {
dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
return;
}
fsleep(1000);
}
}
@@ -323,8 +320,7 @@ static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p,
}
static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
const char *hid,
int id)
const char *hid, int id)
{
struct tasdevice_priv *p = tas_hda->priv;
struct acpi_device *adev;
@@ -341,7 +337,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
}
strscpy(p->dev_name, hid, sizeof(p->dev_name));
tas_hda->dacpi = adev;
physdev = get_device(acpi_get_first_physical_node(adev));
acpi_dev_put(adev);
@@ -410,126 +405,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
}
}
static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
return 0;
}
static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
return 0;
}
static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
int max = tas_priv->rcabin.ncfgs - 1;
int val;
val = clamp(ucontrol->value.integer.value[0], 0, max);
if (tas_priv->rcabin.profile_cfg_id != val) {
tas_priv->rcabin.profile_cfg_id = val;
return 1;
}
return 0;
}
static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
return 0;
}
static int tasdevice_info_config(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = tas_priv->fmw->nr_configurations - 1;
return 0;
}
static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->cur_prog;
return 0;
}
static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
int nr_program = ucontrol->value.integer.value[0];
int max = tas_priv->fmw->nr_programs - 1;
int val;
val = clamp(nr_program, 0, max);
if (tas_priv->cur_prog != val) {
tas_priv->cur_prog = val;
return 1;
}
return 0;
}
static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = tas_priv->cur_conf;
return 0;
}
static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
int max = tas_priv->fmw->nr_configurations - 1;
int val;
val = clamp(ucontrol->value.integer.value[0], 0, max);
if (tas_priv->cur_conf != val) {
tas_priv->cur_conf = val;
return 1;
}
return 0;
}
/*
* tas2781_digital_getvol - get the volum control
* @kcontrol: control pointer
@@ -618,73 +493,37 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
return change;
}
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 0", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
tas2781_amp_putvol, amp_vol_tlv),
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 0", TAS2781_DVC_LVL,
0, 0, 200, 1, tas2781_digital_getvol,
tas2781_digital_putvol, dvc_tlv),
ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 0", 0,
tas2781_force_fwload_get, tas2781_force_fwload_put),
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 1", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
tas2781_amp_putvol, amp_vol_tlv),
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 1", TAS2781_DVC_LVL,
0, 0, 200, 1, tas2781_digital_getvol,
tas2781_digital_putvol, dvc_tlv),
ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 1", 0,
tas2781_force_fwload_get, tas2781_force_fwload_put),
struct snd_kcontrol_new tas2781_snd_ctls[] = {
ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0,
tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv),
ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1,
tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv),
ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get,
tas2781_force_fwload_put),
};
static const struct snd_kcontrol_new tas2781_prof_ctrl[] = {
{
.name = "Speaker Profile Id - 0",
struct snd_kcontrol_new tas2781_prof_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_profile,
.get = tasdevice_get_profile_id,
.put = tasdevice_set_profile_id,
},
{
.name = "Speaker Profile Id - 1",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_profile,
.get = tasdevice_get_profile_id,
.put = tasdevice_set_profile_id,
},
};
static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl[] = {
{
.name = "Speaker Program Id 0",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_programs,
.get = tasdevice_program_get,
.put = tasdevice_program_put,
},
{
.name = "Speaker Program Id 1",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_programs,
.get = tasdevice_program_get,
.put = tasdevice_program_put,
},
};
static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl[] = {
{
.name = "Speaker Config Id 0",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_config,
.get = tasdevice_config_get,
.put = tasdevice_config_put,
},
{
.name = "Speaker Config Id 1",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_config,
.get = tasdevice_config_get,
.put = tasdevice_config_put,
},
struct snd_kcontrol_new tas2781_dsp_ctls[] = {
/* Speaker Program */
{
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_programs,
.get = tasdevice_program_get,
.put = tasdevice_program_put,
},
/* Speaker Config */
{
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = tasdevice_info_config,
.get = tasdevice_config_get,
.put = tasdevice_config_put,
},
};
static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
@@ -853,23 +692,111 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
{
struct hda_codec *codec = tas_hda->priv->codec;
struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv;
snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
for (int i = ARRAY_SIZE(h_priv->snd_ctls) - 1; i >= 0; i--)
snd_ctl_remove(codec->card, h_priv->snd_ctls[i]);
snd_ctl_remove(codec->card, tas_hda->prof_ctl);
}
static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h)
{
struct tasdevice_priv *p = h->priv;
struct hda_codec *c = p->codec;
char name[64];
int rc;
snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index);
tas2781_prof_ctl.name = name;
h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p);
rc = snd_ctl_add(c->card, h->prof_ctl);
if (rc)
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_prof_ctl.name, rc);
return rc;
}
static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h)
{
struct tas2781_hda_spi_priv *h_priv = h->hda_priv;
struct tasdevice_priv *p = h->priv;
struct hda_codec *c = p->codec;
char name[64];
int i = 0;
int rc;
snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index);
tas2781_snd_ctls[i].name = name;
h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
if (rc) {
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_snd_ctls[i].name, rc);
return rc;
}
i++;
snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index);
tas2781_snd_ctls[i].name = name;
h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
if (rc) {
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_snd_ctls[i].name, rc);
return rc;
}
i++;
snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index);
tas2781_snd_ctls[i].name = name;
h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
if (rc) {
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_snd_ctls[i].name, rc);
}
return rc;
}
static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h)
{
struct tasdevice_priv *p = h->priv;
struct hda_codec *c = p->codec;
char name[64];
int i = 0;
int rc;
snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index);
tas2781_dsp_ctls[i].name = name;
h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
rc = snd_ctl_add(c->card, h->dsp_prog_ctl);
if (rc) {
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_dsp_ctls[i].name, rc);
return rc;
}
i++;
snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index);
tas2781_dsp_ctls[i].name = name;
h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
rc = snd_ctl_add(c->card, h->dsp_conf_ctl);
if (rc) {
dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
tas2781_dsp_ctls[i].name, rc);
}
return rc;
}
static void tasdev_fw_ready(const struct firmware *fmw, void *context)
{
struct tasdevice_priv *tas_priv = context;
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
struct hda_codec *codec = tas_priv->codec;
int i, j, ret, val;
int ret, val;
pm_runtime_get_sync(tas_priv->dev);
guard(mutex)(&tas_priv->codec_lock);
@@ -879,33 +806,19 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
goto out;
/* Add control one time only. */
tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl[tas_priv->index],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
if (ret) {
dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
tas2781_prof_ctrl[tas_priv->index].name, ret);
ret = tas2781_hda_spi_prf_ctl(tas_hda);
if (ret)
goto out;
ret = tas2781_hda_spi_snd_ctls(tas_hda);
if (ret)
goto out;
}
j = tas_priv->index * ARRAY_SIZE(tas2781_snd_controls) / 2;
for (i = 0; i < 3; i++) {
tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i+j],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
tas2781_snd_controls[i+tas_priv->index*3].name,
ret);
goto out;
}
}
tasdevice_dsp_remove(tas_priv);
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%08X-%01d.bin",
codec->core.subsystem_id, tas_priv->index);
scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin",
lower_16_bits(codec->core.subsystem_id), tas_priv->index);
ret = tasdevice_dsp_parser(tas_priv);
if (ret) {
dev_err(tas_priv->dev, "dspfw load %s error\n",
@@ -914,33 +827,15 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
goto out;
}
/* Add control one time only. */
tas_hda->dsp_prog_ctl =
snd_ctl_new1(&tas2781_dsp_prog_ctrl[tas_priv->index],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
tas2781_dsp_prog_ctrl[tas_priv->index].name, ret);
ret = tas2781_hda_spi_dsp_ctls(tas_hda);
if (ret)
goto out;
}
tas_hda->dsp_conf_ctl =
snd_ctl_new1(&tas2781_dsp_conf_ctrl[tas_priv->index],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
if (ret) {
dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
tas2781_dsp_conf_ctrl[tas_priv->index].name, ret);
goto out;
}
/* Perform AMP reset before firmware download. */
tas2781_spi_reset(tas_priv);
tas_priv->rcabin.profile_cfg_id = 0;
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
ret = tas_priv->dev_read(tas_priv, tas_priv->index,
ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index,
TAS2781_REG_CLK_CONFIG, &val);
if (ret < 0)
goto out;
@@ -952,6 +847,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
ret);
goto out;
}
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
}
if (tas_priv->fmw->nr_programs > 0)
tas_priv->tasdevice[tas_priv->index].cur_prog = 0;
@@ -962,7 +858,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
*/
tas2781_save_calibration(tas_priv);
out:
release_firmware(fmw);
pm_runtime_mark_last_busy(tas_hda->priv->dev);
@@ -1032,22 +928,9 @@ static const struct component_ops tas2781_hda_comp_ops = {
.unbind = tas2781_hda_unbind,
};
static void tas2781_hda_remove(struct device *dev)
{
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
component_del(tas_hda->priv->dev, &tas2781_hda_comp_ops);
pm_runtime_get_sync(tas_hda->priv->dev);
pm_runtime_disable(tas_hda->priv->dev);
pm_runtime_put_noidle(tas_hda->priv->dev);
mutex_destroy(&tas_hda->priv->codec_lock);
}
static int tas2781_hda_spi_probe(struct spi_device *spi)
{
struct tas2781_hda_spi_priv *hda_priv;
struct tasdevice_priv *tas_priv;
struct tas2781_hda *tas_hda;
const char *device_name;
@@ -1057,6 +940,11 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
if (!tas_hda)
return -ENOMEM;
hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL);
if (!hda_priv)
return -ENOMEM;
tas_hda->hda_priv = hda_priv;
spi->max_speed_hz = TAS2781_SPI_MAX_FREQ;
tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL);
@@ -1087,16 +975,10 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
spi_get_chipselect(spi, 0));
if (ret)
return dev_err_probe(tas_priv->dev, ret,
"Platform not supported\n");
"Platform not supported\n");
tasdevice_spi_init(tas_priv);
ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
if (ret) {
dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
return ret;
}
pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
pm_runtime_use_autosuspend(tas_priv->dev);
pm_runtime_mark_last_busy(tas_priv->dev);
@@ -1106,12 +988,19 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
pm_runtime_put_autosuspend(tas_priv->dev);
return 0;
ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
if (ret) {
dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
pm_runtime_disable(tas_priv->dev);
tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
}
return ret;
}
static void tas2781_hda_spi_remove(struct spi_device *spi)
{
tas2781_hda_remove(&spi->dev);
tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
}
static int tas2781_runtime_suspend(struct device *dev)
@@ -1231,3 +1120,4 @@ MODULE_DESCRIPTION("TAS2781 HDA SPI Driver");
MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");