Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sound/soc/codecs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,7 @@ config SND_SOC_TAS2783_SDW
tristate "Texas Instruments TAS2783 speaker amplifier (sdw)"
depends on SOUNDWIRE
depends on EFI
depends on SND_SOC_SDCA
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
select CRC32
Expand Down
95 changes: 92 additions & 3 deletions sound/soc/codecs/tas2783-sdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw_type.h>
#include <sound/sdca_function.h>
#include <sound/sdw.h>
#include <sound/soc.h>
#include <sound/tlv.h>
Expand All @@ -40,6 +41,7 @@
#define TAS2783_PROBE_TIMEOUT 5000
#define TAS2783_CALI_GUID EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, \
0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92)
#define MIPI_INIT_TABLE "mipi-sdca-function-initialization-table"

static const u32 tas2783_cali_reg[] = {
TAS2783_CAL_R0,
Expand All @@ -56,6 +58,11 @@ struct bin_header_t {
u32 length;
};

struct raw_init_data {
__le32 addr;
u8 val;
} __packed;

struct calibration_data {
u32 is_valid;
unsigned long read_sz;
Expand Down Expand Up @@ -83,6 +90,8 @@ struct tas2783_prv {
wait_queue_head_t fw_wait;
bool fw_dl_task_done;
bool fw_dl_success;
struct reg_sequence *init_data;
int num_init_data;
};

static const struct reg_default tas2783_reg_default[] = {
Expand Down Expand Up @@ -1214,9 +1223,19 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
ret = -EAGAIN;
} else {
ret = regmap_multi_reg_write(tas_dev->regmap, tas2783_init_seq,
ARRAY_SIZE(tas2783_init_seq));
tas_dev->hw_init = true;
if (tas_dev->num_init_data > 0)
ret = regmap_multi_reg_write(tas_dev->regmap,
tas_dev->init_data,
tas_dev->num_init_data);
else
ret = regmap_multi_reg_write(tas_dev->regmap, tas2783_init_seq,
ARRAY_SIZE(tas2783_init_seq));

if (ret)
dev_err(tas_dev->dev,
"init writes failed, err=%d", ret);
else
tas_dev->hw_init = true;
}

return ret;
Expand Down Expand Up @@ -1260,6 +1279,73 @@ static void tas_remove(struct tas2783_prv *tas_dev)
snd_soc_unregister_component(tas_dev->dev);
}

static s32 tas_get_smartamp_init_data(struct sdw_slave *peripheral,
struct tas2783_prv *tas_dev)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse the sdca_parse_function() helper to get the init_table? What do you think? @charleskeepax

{
int num_init_data, i;
struct device *dev;
struct reg_sequence *init_data;
struct sdca_device_data *sdca_data;
struct sdca_function_desc *function;
struct raw_init_data *raw __free(kfree) = NULL;

dev = &peripheral->dev;
sdca_data = &peripheral->sdca_data;

dev_dbg(dev, "number of functions found %d",
sdca_data->num_functions);

if (sdca_data->num_functions <= 0)
return -EINVAL;

/* look for smartamp function */
for (i = 0; i < sdca_data->num_functions; i++) {
if (sdca_data->function[i].type ==
SDCA_FUNCTION_TYPE_SMART_AMP)
break;
}
if (i == sdca_data->num_functions)
return -EINVAL;

function = &sdca_data->function[i];
num_init_data = fwnode_property_count_u8(function->node,
MIPI_INIT_TABLE);
if (num_init_data <= 0) {
dev_dbg(dev, "error reading init table for tas2783 err=%d",
num_init_data);
return num_init_data;
}

if (num_init_data % sizeof(*raw) != 0) {
dev_dbg(dev, "%s should be integer multiple of %lu",
MIPI_INIT_TABLE, sizeof(*raw));
return -EINVAL;
}

raw = kzalloc(num_init_data, GFP_KERNEL);
if (!raw)
return -ENOMEM;

fwnode_property_read_u8_array(function->node, MIPI_INIT_TABLE,
(u8 *)raw, num_init_data);

num_init_data /= sizeof(*raw);
init_data = devm_kcalloc(dev, num_init_data, sizeof(*init_data),
GFP_KERNEL);
if (!init_data)
return -ENOMEM;

for (i = 0; i < num_init_data; i++) {
init_data[i].reg = le32_to_cpu(raw[i].addr);
init_data[i].def = raw[i].val;
}

tas_dev->num_init_data = num_init_data;
tas_dev->init_data = init_data;

return 0;
}

static s32 tas_sdw_probe(struct sdw_slave *peripheral,
const struct sdw_device_id *id)
{
Expand All @@ -1272,6 +1358,8 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
return dev_err_probe(dev, -ENOMEM,
"Failed devm_kzalloc");

tas_get_smartamp_init_data(peripheral, tas_dev);

tas_dev->dev = dev;
tas_dev->sdw_peripheral = peripheral;
tas_dev->hw_init = false;
Expand Down Expand Up @@ -1325,6 +1413,7 @@ static struct sdw_driver tas_sdw_driver = {
};
module_sdw_driver(tas_sdw_driver);

MODULE_IMPORT_NS("SND_SOC_SDCA");
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("ASoC TAS2783 SoundWire Driver");
MODULE_LICENSE("GPL");
4 changes: 4 additions & 0 deletions sound/soc/sdw_utils/soc_sdw_ti_amp.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ int asoc_sdw_ti_spk_rtd_init(struct snd_soc_pcm_runtime *rtd,
strscpy(speaker, "Left Spk", sizeof(speaker));
} else if (!strncmp(prefix, "tas2783-2", strlen("tas2783-2"))) {
strscpy(speaker, "Right Spk", sizeof(speaker));
} else if (!strncmp(prefix, "tas2783-3", strlen("tas2783-3"))) {
strscpy(speaker, "Left Spk2", sizeof(speaker));
} else if (!strncmp(prefix, "tas2783-4", strlen("tas2783-4"))) {
strscpy(speaker, "Right Spk2", sizeof(speaker));
} else {
ret = -EINVAL;
dev_err(card->dev, "unhandled prefix %s", prefix);
Expand Down
22 changes: 18 additions & 4 deletions sound/soc/sdw_utils/soc_sdw_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,25 @@ static const struct snd_soc_dapm_widget lr_spk_widgets[] = {
SND_SOC_DAPM_SPK("Right Spk", NULL),
};

static const struct snd_soc_dapm_widget lr_4spk_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_SPK("Left Spk2", NULL),
SND_SOC_DAPM_SPK("Right Spk2", NULL),
};

static const struct snd_kcontrol_new lr_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
};

static const struct snd_kcontrol_new lr_4spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
SOC_DAPM_PIN_SWITCH("Left Spk2"),
SOC_DAPM_PIN_SWITCH("Right Spk2"),
};

static const struct snd_soc_dapm_widget rt700_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
Expand All @@ -69,10 +83,10 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
.init = asoc_sdw_ti_amp_init,
.rtd_init = asoc_sdw_ti_spk_rtd_init,
.controls = lr_spk_controls,
.num_controls = ARRAY_SIZE(lr_spk_controls),
.widgets = lr_spk_widgets,
.num_widgets = ARRAY_SIZE(lr_spk_widgets),
.controls = lr_4spk_controls,
.num_controls = ARRAY_SIZE(lr_4spk_controls),
.widgets = lr_4spk_widgets,
.num_widgets = ARRAY_SIZE(lr_4spk_widgets),
},
},
.dai_num = 1,
Expand Down