[PATCH v1 1/8] ASoC: tas2783A: sdw_utils: support ch 3 & 4
Currently the machine driver for tas2783A can only support 2 channels. This patch adds support for 2 channel playback with 4 device setup.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/sdw_utils/soc_sdw_ti_amp.c | 4 ++++ sound/soc/sdw_utils/soc_sdw_utils.c | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sdw_utils/soc_sdw_ti_amp.c b/sound/soc/sdw_utils/soc_sdw_ti_amp.c index cbd60faec..488ef2ef4 100644 --- a/sound/soc/sdw_utils/soc_sdw_ti_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_ti_amp.c @@ -58,6 +58,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); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 824fb613c..ec00f13a6 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -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), @@ -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,
Use the firmware version same as in Windows projects. The firmware contains algorithm parameters and some device configuration writes which are part of the same firmware file.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/tas2783-sdw.c | 147 +++++++++++++++++++-------------- sound/soc/codecs/tas2783.h | 1 + 2 files changed, 85 insertions(+), 63 deletions(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 43b779873..6a0644670 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -35,8 +35,8 @@ #include "tas2783.h"
#define TIMEOUT_FW_DL_MS (3000) -#define FW_DL_OFFSET 36 -#define FW_FL_HDR 12 +#define FW_DL_OFFSET 84 /* binary file information */ +#define FW_FL_HDR 20 /* minimum number of bytes in one chunk */ #define TAS2783_PROBE_TIMEOUT 5000 #define TAS2783_CALI_GUID EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, \ 0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92) @@ -49,11 +49,22 @@ static const u32 tas2783_cali_reg[] = { TAS2783_CAL_TLIM, };
-struct bin_header_t { - u16 vendor_id; - u16 version; +struct tas_fw_hdr { + u32 size; + u32 version_offset; + u32 plt_id; + u32 ppc3_ver; + u32 timestamp; + u8 ddc_name[64]; +}; + +struct tas_fw_file { + u32 vendor_id; u32 file_id; + u32 version; u32 length; + u32 dest_addr; + u8 *fw_data; };
struct calibration_data { @@ -735,13 +746,28 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev) return ret; }
-static s32 read_header(const u8 *data, struct bin_header_t *hdr) +static s32 tas_fw_read_hdr(const u8 *data, struct tas_fw_hdr *hdr) +{ + hdr->size = get_unaligned_le32(data); + hdr->version_offset = get_unaligned_le32(&data[4]); + hdr->plt_id = get_unaligned_le32(&data[8]); + hdr->ppc3_ver = get_unaligned_le32(&data[12]); + memcpy(hdr->ddc_name, &data[16], 64); + hdr->timestamp = get_unaligned_le32(&data[80]); + + return 84; +} + +static s32 tas_fw_get_next_file(const u8 *data, struct tas_fw_file *file) { - hdr->vendor_id = get_unaligned_le16(&data[0]); - hdr->file_id = get_unaligned_le32(&data[2]); - hdr->version = get_unaligned_le16(&data[6]); - hdr->length = get_unaligned_le32(&data[8]); - return 12; + file->vendor_id = get_unaligned_le32(&data[0]); + file->file_id = get_unaligned_le32(&data[4]); + file->version = get_unaligned_le32(&data[8]); + file->length = get_unaligned_le32(&data[12]); + file->dest_addr = get_unaligned_le32(&data[16]); + file->fw_data = (u8 *)&data[20]; + + return file->length + sizeof(u32) * 5; }
static void tas2783_fw_ready(const struct firmware *fmw, void *context) @@ -749,13 +775,20 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context) struct tas2783_prv *tas_dev = (struct tas2783_prv *)context; const u8 *buf = NULL; - s32 offset = 0, img_sz, file_blk_size, ret; - struct bin_header_t hdr; + s32 img_sz, ret = 0, cur_file = 0; + s32 offset = 0; + + struct tas_fw_hdr *hdr __free(kfree) = kzalloc(sizeof(*hdr), GFP_KERNEL); + struct tas_fw_file *file __free(kfree) = kzalloc(sizeof(*file), GFP_KERNEL); + if (!file || !hdr) { + ret = -ENOMEM; + goto out; + }
if (!fmw || !fmw->data) { - /* No firmware binary, devices will work in ROM mode. */ + /* firmware binary not found*/ dev_err(tas_dev->dev, - "Failed to read %s, no side-effect on driver running\n", + "Failed to read fw binary %s\n", tas_dev->rca_binaryname); ret = -EINVAL; goto out; @@ -763,67 +796,47 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
img_sz = fmw->size; buf = fmw->data; - offset += FW_DL_OFFSET; - if (offset >= (img_sz - FW_FL_HDR)) { - dev_err(tas_dev->dev, - "firmware is too small"); + offset += tas_fw_read_hdr(buf, hdr); + if (hdr->size != img_sz) { ret = -EINVAL; + dev_err(tas_dev->dev, "firmware size mismatch with header"); + goto out; + } + + if (img_sz < FW_DL_OFFSET) { + ret = -EINVAL; + dev_err(tas_dev->dev, "unexpected size, size is too small"); goto out; }
mutex_lock(&tas_dev->pde_lock); while (offset < (img_sz - FW_FL_HDR)) { - memset(&hdr, 0, sizeof(hdr)); - offset += read_header(&buf[offset], &hdr); + offset += tas_fw_get_next_file(&buf[offset], file); dev_dbg(tas_dev->dev, - "vndr=%d, file=%d, version=%d, len=%d, off=%d\n", - hdr.vendor_id, hdr.file_id, hdr.version, - hdr.length, offset); - /* size also includes the header */ - file_blk_size = hdr.length - FW_FL_HDR; - - /* make sure that enough data is there */ - if (offset + file_blk_size > img_sz) { - ret = -EINVAL; + "v=%d, fid=%d, ver=%d, len=%d, daddr=0x%x, fw=%p", + file->vendor_id, file->file_id, + file->version, file->length, + file->dest_addr, file->fw_data); + + ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral, + file->dest_addr, + file->length, + file->fw_data); + if (ret < 0) { dev_err(tas_dev->dev, - "corrupt firmware file"); + "FW download failed: %d", ret); break; } - - switch (hdr.file_id) { - case 0: - ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral, - PRAM_ADDR_START, file_blk_size, - &buf[offset]); - if (ret < 0) - dev_err(tas_dev->dev, - "PRAM update failed: %d", ret); - break; - - case 1: - ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral, - YRAM_ADDR_START, file_blk_size, - &buf[offset]); - if (ret < 0) - dev_err(tas_dev->dev, - "YRAM update failed: %d", ret); - - break; - - default: - ret = -EINVAL; - dev_err(tas_dev->dev, "Unsupported file"); - break; - } - - if (ret == 0) - offset += file_blk_size; - else - break; + cur_file++; } mutex_unlock(&tas_dev->pde_lock); - if (!ret) + + if (cur_file == 0) { + dev_err(tas_dev->dev, "fw with no files"); + ret = -EINVAL; + } else { tas2783_update_calibdata(tas_dev); + }
out: if (!ret) @@ -1211,6 +1224,14 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
tas_dev->fw_dl_task_done = false; tas_dev->fw_dl_success = false; + + ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1); + if (ret) { + dev_err(dev, "sw reset failed, err=%d", ret); + return ret; + } + usleep_range(2000, 2200); + scnprintf(tas_dev->rca_binaryname, sizeof(tas_dev->rca_binaryname), "tas2783-%01x.bin", unique_id);
diff --git a/sound/soc/codecs/tas2783.h b/sound/soc/codecs/tas2783.h index 794333e0a..bf34319c9 100644 --- a/sound/soc/codecs/tas2783.h +++ b/sound/soc/codecs/tas2783.h @@ -28,6 +28,7 @@ #define TASDEV_REG_SDW(book, page, reg) (((book) * 256 * 128) + \ 0x800000 + ((page) * 128) + (reg))
+#define TAS2783_SW_RESET TASDEV_REG_SDW(0x0, 0x00, 0x01) /* Volume control */ #define TAS2783_DVC_LVL TASDEV_REG_SDW(0x0, 0x00, 0x1A) #define TAS2783_AMP_LEVEL TASDEV_REG_SDW(0x0, 0x00, 0x03)
Remove unwanted initialistaion writes to the device which will now be part of the either firmware or acpi table.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/tas2783-sdw.c | 54 +--------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 6a0644670..bfa925dd6 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -297,7 +297,7 @@ static const struct reg_default tas2783_reg_default[] = { };
static const struct reg_sequence tas2783_init_seq[] = { - REG_SEQ0(SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0x00), 0x04), + REG_SEQ0(SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0x00), 0x01), REG_SEQ0(0x00800418, 0x00), REG_SEQ0(0x00800419, 0x00), REG_SEQ0(0x0080041a, 0x00), @@ -307,60 +307,19 @@ static const struct reg_sequence tas2783_init_seq[] = { REG_SEQ0(0x0080042a, 0x00), REG_SEQ0(0x0080042b, 0x00), REG_SEQ0(SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x1, 0x00), 0x00), - REG_SEQ0(0x0080005c, 0xD9), - REG_SEQ0(0x00800082, 0x20), - REG_SEQ0(0x008000a1, 0x00), - REG_SEQ0(0x00800097, 0xc8), - REG_SEQ0(0x00800099, 0x20), - REG_SEQ0(0x008000c7, 0xaa), - REG_SEQ0(0x008000b5, 0x74), - REG_SEQ0(0x00800082, 0x20), - REG_SEQ0(0x00807e8d, 0x0d), - REG_SEQ0(0x00807eb9, 0x53), - REG_SEQ0(0x00807ebe, 0x42), - REG_SEQ0(0x00807ec5, 0x37), - REG_SEQ0(0x00800066, 0x92), - REG_SEQ0(0x00800003, 0x28), REG_SEQ0(0x00800004, 0x21), REG_SEQ0(0x00800005, 0x41), REG_SEQ0(0x00800006, 0x00), REG_SEQ0(0x00800007, 0x20), - REG_SEQ0(0x0080000c, 0x10), - REG_SEQ0(0x00800013, 0x08), REG_SEQ0(0x00800015, 0x00), - REG_SEQ0(0x00800017, 0x80), - REG_SEQ0(0x0080001a, 0x00), - REG_SEQ0(0x0080001b, 0x22), - REG_SEQ0(0x0080001c, 0x36), - REG_SEQ0(0x0080001d, 0x01), - REG_SEQ0(0x0080001f, 0x00), - REG_SEQ0(0x00800020, 0x2e), - REG_SEQ0(0x00800034, 0x06), - REG_SEQ0(0x00800035, 0xb9), REG_SEQ0(0x00800036, 0xad), REG_SEQ0(0x00800037, 0xa8), - REG_SEQ0(0x00800038, 0x00), - REG_SEQ0(0x0080003b, 0xfc), - REG_SEQ0(0x0080003d, 0xdd), - REG_SEQ0(0x00800040, 0xf6), - REG_SEQ0(0x00800041, 0x14), - REG_SEQ0(0x0080005c, 0x19), - REG_SEQ0(0x0080005d, 0x80), - REG_SEQ0(0x00800063, 0x48), - REG_SEQ0(0x00800065, 0x08), - REG_SEQ0(0x00800067, 0x00), - REG_SEQ0(0x0080006a, 0x12), REG_SEQ0(0x0080006b, 0x7b), REG_SEQ0(0x0080006c, 0x00), REG_SEQ0(0x0080006d, 0x00), REG_SEQ0(0x0080006e, 0x1a), REG_SEQ0(0x0080006f, 0x00), - REG_SEQ0(0x00800070, 0x96), REG_SEQ0(0x00800071, 0x02), - REG_SEQ0(0x00800073, 0x08), - REG_SEQ0(0x00800075, 0xe0), - REG_SEQ0(0x0080007a, 0x60), - REG_SEQ0(0x008000bd, 0x00), REG_SEQ0(0x008000be, 0x00), REG_SEQ0(0x008000bf, 0x00), REG_SEQ0(0x008000c0, 0x00), @@ -368,17 +327,6 @@ static const struct reg_sequence tas2783_init_seq[] = { REG_SEQ0(0x008000c2, 0x00), REG_SEQ0(0x008000c3, 0x00), REG_SEQ0(0x008000c4, 0x00), - REG_SEQ0(0x008000c5, 0x00), - REG_SEQ0(0x00800008, 0x49), - REG_SEQ0(0x00800009, 0x02), - REG_SEQ0(0x0080000a, 0x1a), - REG_SEQ0(0x0080000d, 0x93), - REG_SEQ0(0x0080000e, 0x82), - REG_SEQ0(0x0080000f, 0x42), - REG_SEQ0(0x00800010, 0x84), - REG_SEQ0(0x00800014, 0x0a), - REG_SEQ0(0x00800016, 0x00), - REG_SEQ0(0x00800060, 0x21), };
static int tas2783_sdca_mbq_size(struct device *dev, u32 reg)
Currently when the calibration is not foun, it is wrongly logged as device is not found. Fix this error message to indicate that calibration data is not valid instead.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/tas2783-sdw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index bfa925dd6..397442cd6 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -635,7 +635,8 @@ static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32 }
if (device_num == dev_count) - dev_err(tas_dev->dev, "device not found\n"); + dev_err(tas_dev->dev, + "unique id not found in the calib data\n"); else dev_dbg(tas_dev->dev, "calib data update done\n"); }
The firmware file for tas2783A contains the device and algorithm settings. So the firmware files are unique for a system and driver should have the ability to distinctly identify and pick the right firmware.
This commit adds the method to uniquely identify the firmware for a system based on the below format. <Subsystem>-<Link>-<Unique>.bin
* Subsystem is the PCI device subsystem-id * Link is the SoundWire link id on which the device recides. * Unique is the SoundWire slave unique id in the system.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/tas2783-sdw.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 397442cd6..adfbccedb 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -27,6 +27,7 @@ #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_type.h> +#include <linux/pci.h> #include <sound/sdw.h> #include <sound/soc.h> #include <sound/tlv.h> @@ -1162,8 +1163,21 @@ static const struct dev_pm_ops tas2783_sdca_pm = { RUNTIME_PM_OPS(tas2783_sdca_dev_suspend, tas2783_sdca_dev_resume, NULL) };
+static struct pci_dev *tas_get_pci_dev(struct sdw_slave *peripheral) +{ + struct device *dev = &peripheral->dev; + + for (; dev; dev = dev->parent) + if (dev->bus == &pci_bus_type) + return to_pci_dev(dev); + + return NULL; +} + static s32 tas_io_init(struct device *dev, struct sdw_slave *slave) { + struct pci_dev *pci; + struct sdw_bus *bus; struct tas2783_prv *tas_dev = dev_get_drvdata(dev); s32 ret; u8 unique_id = tas_dev->sdw_peripheral->id.unique_id; @@ -1171,6 +1185,13 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave) if (tas_dev->hw_init) return 0;
+ pci = tas_get_pci_dev(slave); + if (!pci) { + dev_err(dev, "pci device id can't be read"); + return -EINVAL; + } + + bus = slave->bus; tas_dev->fw_dl_task_done = false; tas_dev->fw_dl_success = false;
@@ -1181,8 +1202,10 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave) } usleep_range(2000, 2200);
+ /* subsystem_id-link_id-unique_id */ scnprintf(tas_dev->rca_binaryname, sizeof(tas_dev->rca_binaryname), - "tas2783-%01x.bin", unique_id); + "%04X-%1X-%1X.bin", pci->subsystem_device, bus->link_id, + unique_id);
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, tas_dev->rca_binaryname, tas_dev->dev,
Add changes to support 4 tas2783A devices on mtl platform. The supported unique IDs are updated to 9, a, c, d, where c and d are configured to play left channels and 9 and a are configured to play right channel.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index ec9fd8486..f12d42986 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -950,7 +950,7 @@ static const struct snd_soc_acpi_adr_device cs42l42_0_adr[] = {
static const struct snd_soc_acpi_adr_device tas2783_0_adr[] = { { - .adr = 0x0000380102000001ull, + .adr = 0x00003c0102000001ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "tas2783-1" @@ -960,6 +960,18 @@ static const struct snd_soc_acpi_adr_device tas2783_0_adr[] = { .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "tas2783-2" + }, + { + .adr = 0x00003d0102000001ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "tas2783-3" + }, + { + .adr = 0x00003a0102000001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "tas2783-4" } };
This patch adds support for parsing the initilisation data from ACPI table. This table is required to configure each device correctly so that correct channel's data is selected during playback.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/tas2783-sdw.c | 61 +++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 433af9bc7..94d66e4d5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2146,6 +2146,7 @@ config SND_SOC_TAS2781_I2C config SND_SOC_TAS2783_SDW tristate "Texas Instruments TAS2783 speaker amplifier (sdw)" depends on SOUNDWIRE + depends on SND_SOC_SDCA depends on EFI select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index adfbccedb..5be163664 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -32,6 +32,7 @@ #include <sound/soc.h> #include <sound/tlv.h> #include <sound/tas2781-tlv.h> +#include <sound/sdca_function.h>
#include "tas2783.h"
@@ -78,6 +79,7 @@ struct tas2783_prv { struct snd_soc_component *component; struct calibration_data cali_data; struct sdw_slave *sdw_peripheral; + struct sdca_function_data *sa_func_data; enum sdw_slave_status status; /* calibration */ struct mutex calib_lock; @@ -1179,7 +1181,7 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave) struct pci_dev *pci; struct sdw_bus *bus; struct tas2783_prv *tas_dev = dev_get_drvdata(dev); - s32 ret; + s32 ret, i; u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
if (tas_dev->hw_init) @@ -1223,9 +1225,24 @@ 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->sa_func_data) { + for (i = 0; i < tas_dev->sa_func_data->num_init_table; i++) { + ret = regmap_write(tas_dev->regmap, + tas_dev->sa_func_data->init_table[i].addr, + tas_dev->sa_func_data->init_table[i].val); + if (ret) + break; + } + } 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; @@ -1275,12 +1292,47 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral, struct regmap *regmap; struct device *dev = &peripheral->dev; struct tas2783_prv *tas_dev; + struct sdca_function_data *function_data = NULL; + int ret, i;
tas_dev = devm_kzalloc(dev, sizeof(*tas_dev), GFP_KERNEL); if (!tas_dev) return dev_err_probe(dev, -ENOMEM, "Failed devm_kzalloc");
+ i = -1; + /* check if we have any SDCA function data available */ + if (peripheral->sdca_data.num_functions > 0) { + dev_dbg(dev, "SDCA functions found: %d", peripheral->sdca_data.num_functions); + + /* Look for Smart Amp function type */ + for (i = 0; i < peripheral->sdca_data.num_functions; i++) { + if (peripheral->sdca_data.function[i].type == + SDCA_FUNCTION_TYPE_SMART_AMP) { + dev_info(dev, "Found Smart Amp function at index %d", i); + break; + } + } + } + + if (i >= 0 && i < peripheral->sdca_data.num_functions) { + /* Allocate memory for function data */ + function_data = devm_kzalloc(dev, sizeof(*function_data), + GFP_KERNEL); + if (!function_data) + return dev_err_probe(dev, -ENOMEM, + "failed to parse sdca functions"); + + /* Parse the function */ + ret = sdca_parse_function(dev, peripheral, + &peripheral->sdca_data.function[i], + function_data); + if (!ret) + tas_dev->sa_func_data = function_data; + else + dev_warn(dev, "smartamp function parse failed:err%d, using defaults", ret); + } + tas_dev->dev = dev; tas_dev->sdw_peripheral = peripheral; tas_dev->hw_init = false; @@ -1335,6 +1387,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");
On Thu, Nov 20, 2025 at 02:50:49PM +0530, Niranjan H Y wrote:
This patch adds support for parsing the initilisation data from ACPI table. This table is required to configure each device correctly so that correct channel's data is selected during playback.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com
sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/tas2783-sdw.c | 61 +++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 433af9bc7..94d66e4d5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2146,6 +2146,7 @@ config SND_SOC_TAS2781_I2C config SND_SOC_TAS2783_SDW tristate "Texas Instruments TAS2783 speaker amplifier (sdw)" depends on SOUNDWIRE
- depends on SND_SOC_SDCA
Great to see some of the SDCA library stuff starting to be useful for people :-)
ret = regmap_multi_reg_write(tas_dev->regmap, tas2783_init_seq,ARRAY_SIZE(tas2783_init_seq));tas_dev->hw_init = true;
if (tas_dev->sa_func_data) {for (i = 0; i < tas_dev->sa_func_data->num_init_table; i++) {ret = regmap_write(tas_dev->regmap,tas_dev->sa_func_data->init_table[i].addr,tas_dev->sa_func_data->init_table[i].val);if (ret)break;}
Should be able to use sdca_regmap_write_init() here once the patch is merged:
https://lore.kernel.org/linux-sound/20251106114422.906370-11-ckeepax@opensou...
No point holding up this patch for it, but would be good to move it across once the core function is merged. And if you wanted to test the core patch out check it works for you that would be amazing.
} 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);elsetas_dev->hw_init = true;}
/* check if we have any SDCA function data available */
if (peripheral->sdca_data.num_functions > 0) {
dev_dbg(dev, "SDCA functions found: %d", peripheral->sdca_data.num_functions);/* Look for Smart Amp function type */for (i = 0; i < peripheral->sdca_data.num_functions; i++) {if (peripheral->sdca_data.function[i].type ==SDCA_FUNCTION_TYPE_SMART_AMP) {dev_info(dev, "Found Smart Amp function at index %d", i);break;}}}
I do wonder if we should add a core function for this search, I am guessing this will become a fairly common pattern. But again no need to hold up your patches for that.
Reviewed-by: Charles Keepax ckeepax@opensource.cirrus.com
Thanks, Charles
Currently device is using hardcoded slave properties using the .read_prop callback from "struct sdw_slave_ops". This patch removes this and uses the sdw_slave_read_prop API to read the data directly from the ACPI table.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com --- sound/soc/codecs/tas2783-sdw.c | 66 +++------------------------------- 1 file changed, 5 insertions(+), 61 deletions(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 5be163664..c5f0c0f93 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -1059,66 +1059,6 @@ static s32 tas_init(struct tas2783_prv *tas_dev) return ret; }
-static s32 tas_read_prop(struct sdw_slave *slave) -{ - struct sdw_slave_prop *prop = &slave->prop; - s32 nval; - s32 i, j; - u32 bit; - unsigned long addr; - struct sdw_dpn_prop *dpn; - - prop->scp_int1_mask = - SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; - prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; - - prop->paging_support = true; - - /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = 0x04; /* BITMAP: 00000100 */ - prop->sink_ports = 0x2; /* BITMAP: 00000010 */ - - nval = hweight32(prop->source_ports); - prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->src_dpn_prop), GFP_KERNEL); - if (!prop->src_dpn_prop) - return -ENOMEM; - - i = 0; - dpn = prop->src_dpn_prop; - addr = prop->source_ports; - for_each_set_bit(bit, &addr, 32) { - dpn[i].num = bit; - dpn[i].type = SDW_DPN_FULL; - dpn[i].simple_ch_prep_sm = false; - dpn[i].ch_prep_timeout = 10; - i++; - } - - /* do this again for sink now */ - nval = hweight32(prop->sink_ports); - prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), GFP_KERNEL); - if (!prop->sink_dpn_prop) - return -ENOMEM; - - j = 0; - dpn = prop->sink_dpn_prop; - addr = prop->sink_ports; - for_each_set_bit(bit, &addr, 32) { - dpn[j].num = bit; - dpn[j].type = SDW_DPN_FULL; - dpn[j].simple_ch_prep_sm = false; - dpn[j].ch_prep_timeout = 10; - j++; - } - - /* set the timeout values */ - prop->clk_stop_timeout = 200; - - return 0; -} - static s32 tas2783_sdca_dev_suspend(struct device *dev) { struct tas2783_prv *tas_dev = dev_get_drvdata(dev); @@ -1277,7 +1217,6 @@ static s32 tas_update_status(struct sdw_slave *slave, }
static const struct sdw_slave_ops tas_sdw_ops = { - .read_prop = tas_read_prop, .update_status = tas_update_status, };
@@ -1295,6 +1234,11 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral, struct sdca_function_data *function_data = NULL; int ret, i;
+ ret = sdw_slave_read_prop(peripheral); + if (ret) + return dev_err_probe(dev, ret, + "slave property read failed"); + tas_dev = devm_kzalloc(dev, sizeof(*tas_dev), GFP_KERNEL); if (!tas_dev) return dev_err_probe(dev, -ENOMEM,
On Thu, Nov 20, 2025 at 02:50:50PM +0530, Niranjan H Y wrote:
Currently device is using hardcoded slave properties using the .read_prop callback from "struct sdw_slave_ops". This patch removes this and uses the sdw_slave_read_prop API to read the data directly from the ACPI table.
Signed-off-by: Niranjan H Y niranjan.hy@ti.com
Reviewed-by: Charles Keepax ckeepax@opensource.cirrus.com
Thanks, Charles
participants (2)
-
Charles Keepax -
Niranjan H Y