diff options
| author | Mark Brown <broonie@kernel.org> | 2026-09-09 13:16:13 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-09-09 13:16:13 +0100 |
| commit | b4ed6a40b7ddaa3fc4bd8ed75969e57315900154 (patch) | |
| tree | f6e717aaff222e09c3dd44e66e76aed8855528c0 | |
| parent | 3df6761104162d3428aacbc23daf6243cdf7bdd5 (diff) | |
| parent | f4ffa38209499d6991fdade6ec1d2cc8741127e4 (diff) | |
| download | linux-next-b4ed6a40b7ddaa3fc4bd8ed75969e57315900154.tar.gz linux-next-b4ed6a40b7ddaa3fc4bd8ed75969e57315900154.zip | |
ASoC: tas2783-sdw: fix the read-only Control handling
Andrey Golovko <andrey.golovko@gmail.com> says:
The 1/2 of v2 is in for-7.3 as 0c7aeb0f5ece, so this is the rest of it,
rebased on that, with one more patch in front.
Mark asked whether marking the read-only Controls volatile works for
multi-byte reads. It does not, on its own. Twenty of the Controls that
patch marks volatile are wider than one byte: nineteen of four - the
Latency of FU23, FU26 and FU127, XU22 0x06, SAPU29 0x05, PPU21 and PPU26
0x06, the 0x08 Control of IT21, IT26, IT28, IT29, OT23, OT24, OT25, OT28
and OT127, MU26 0x06, MFPU21 and MFPU26 0x08 - and XU22 0x07 of two.
With val_bits = 8 the MBQ layer refuses each of them before anything
reaches the bus, so the patch on its own would turn a read that used to
be answered from the cache into -EINVAL. What the cache answered was
the placeholder from tas2783_reg_default[] rather than anything the
device had said, and the driver performs no register reads at all, so
nothing in tree can tell the difference today - but -EINVAL is not what
the patch should leave behind.
1/2 widens val_bits to 32 and repairs the one place that relied on the
old width, the calibration write, which used regmap_bulk_write() to
spread a four-byte value over four one-byte registers.
Both patches have been running on an ASUS ProArt PX13 (HN7306EAC, two
TAS2783 on one AMD ACP link) since 13 August - the 2/2 in that kernel is
the pre-v2 one, differing only in the File Download Status handling.
Playback, suspend to idle and the calibration path are unaffected.
Link: https://patch.msgid.link/20260815112000.4180-1-andrey.golovko@gmail.com
| -rw-r--r-- | sound/soc/codecs/tas2783-sdw.c | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index eaebb0ebbe0d..1d31b3bfb1ad 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -185,35 +185,17 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0}, @@ -222,40 +204,28 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 5), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0}, @@ -286,7 +256,6 @@ static const struct reg_default tas2783_reg_default[] = { {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0}, - {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0}, {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0}, @@ -495,15 +464,15 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg) return tas2783_sdca_mbq_size(dev, reg) > 0; } -static bool tas2783_writeable_register(struct device *dev, unsigned int reg) +/* + * The read-only SDCA Controls the driver describes: the Latency of every + * Entity, the Clock Valid of every Clock Source, the actual power state of + * the Power Domain Entity, the protection status, the algorithm ready flag + * and the Extension Unit id, version and firmware download status. None of + * them is a setting; every one is a reading of device state. + */ +static bool tas2783_read_only_control(unsigned int reg) { - /* - * The Latency Control of every Entity, together with the Power Domain - * actual state and the protection status, is read-only. They are - * listed in tas2783_reg_default[] with a placeholder value, so without - * this a regcache_sync() would try to write them back and the - * peripheral would reject the transaction, aborting the sync. - */ switch (reg) { case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0): case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0): @@ -538,16 +507,33 @@ static bool tas2783_writeable_register(struct device *dev, unsigned int reg) case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0): case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0): case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0): - return false; + return true; default: - return tas2783_sdca_mbq_size(dev, reg) > 0; + return false; } } +static bool tas2783_writeable_register(struct device *dev, unsigned int reg) +{ + if (tas2783_read_only_control(reg)) + return false; + + return tas2783_sdca_mbq_size(dev, reg) > 0; +} + static bool tas2783_volatile_register(struct device *dev, u32 reg) { + if (tas2783_read_only_control(reg)) + return true; + switch (reg) { + /* + * The File Download Status is a handshake: the device raises its own + * bits on its own schedule and the host writes back a response, so it + * is writable, but it must never be answered from the cache. + */ + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x14, 0): case 0x000 ... 0x080: /* Data port 0. */ case 0x100 ... 0x140: /* Data port 1. */ case 0x200 ... 0x240: /* Data port 2. */ @@ -564,7 +550,13 @@ static bool tas2783_volatile_register(struct device *dev, u32 reg) static const struct regmap_config tas_regmap = { .reg_bits = 32, - .val_bits = 8, + /* + * tas2783_sdca_mbq_size() declares registers of one, two and four + * bytes. val_bits has to cover the widest of those: the SoundWire MBQ + * bus rejects any register whose declared size exceeds val_bits, which + * would make every multi-byte register unreachable in both directions. + */ + .val_bits = 32, .readable_reg = tas2783_readable_register, .writeable_reg = tas2783_writeable_register, .volatile_reg = tas2783_volatile_register, @@ -667,9 +659,9 @@ static s32 tas2783_validate_calibdata(struct tas2783_prv *tas_dev, static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32 *cali_data) { - u32 dev_count, offset, i, device_num; + u32 dev_count, offset, i, j, device_num; u32 reg_value; - u8 buf[4]; + s32 ret; dev_count = cali_data[1]; offset = 3; @@ -683,12 +675,25 @@ static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32 for (i = 0; i < ARRAY_SIZE(tas2783_cali_reg); i++) { reg_value = cali_data[offset + i]; - buf[0] = reg_value >> 24; - buf[1] = reg_value >> 16; - buf[2] = reg_value >> 8; - buf[3] = reg_value & 0xff; - regmap_bulk_write(tas_dev->regmap, tas2783_cali_reg[i], - buf, sizeof(u32)); + + /* + * A calibration value occupies four consecutive + * single-byte registers, most significant byte first. + * Write them one by one: these registers are declared + * as one byte wide by tas2783_sdca_mbq_size(), so a + * multi-byte regmap access would not match the layout. + */ + for (j = 0; j < sizeof(u32); j++) { + ret = regmap_write(tas_dev->regmap, + tas2783_cali_reg[i] + j, + (reg_value >> (24 - 8 * j)) & 0xff); + if (ret) { + dev_err(tas_dev->dev, + "calib write to 0x%x failed, err=%d\n", + tas2783_cali_reg[i] + j, ret); + break; + } + } } break; } |
