From ca1b11b36d8231a748c77e4732e40de9998fa9d8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Apr 2026 13:46:20 +0100 Subject: [PATCH 1/2] regmap: sdw-mbq: Allow defers on undeferrable controls It is a fairly common DisCo issue to have the deferrability of controls marked incorrectly and Windows seems very permissive in this regard. As there isn't really any down side to trying a defer even if the control isn't deferrable, allow this but add a warning message. Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20260413124621.1345315-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-sdw-mbq.c | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c index 6a61629f5f89..4533fe793c5f 100644 --- a/drivers/base/regmap/regmap-sdw-mbq.c +++ b/drivers/base/regmap/regmap-sdw-mbq.c @@ -74,7 +74,7 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg, static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave, unsigned int reg, unsigned int val, - int mbq_size, bool deferrable) + int mbq_size) { int shift = mbq_size * BITS_PER_BYTE; int ret; @@ -88,17 +88,14 @@ static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave, return ret; } - ret = sdw_write_no_pm(slave, reg, val & 0xff); - if (deferrable && ret == -ENODATA) - return -EAGAIN; - - return ret; + return sdw_write_no_pm(slave, reg, val & 0xff); } static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val) { struct regmap_mbq_context *ctx = context; struct sdw_slave *slave = ctx->sdw; + struct device *dev = ctx->dev; bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg); int mbq_size = regmap_sdw_mbq_size(ctx, reg); int ret; @@ -113,13 +110,16 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va * process a single wait/timeout on function busy and a single retry * of the transaction. */ - ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, deferrable); - if (ret == -EAGAIN) { + ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size); + if (ret == -ENODATA) { + if (!deferrable) + dev_warn(dev, "Defer on undeferrable control: %x\n", reg); + ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); if (ret) return ret; - ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, false); + ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size); } return ret; @@ -127,18 +127,14 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave, unsigned int reg, unsigned int *val, - int mbq_size, bool deferrable) + int mbq_size) { int shift = BITS_PER_BYTE; int read; read = sdw_read_no_pm(slave, reg); - if (read < 0) { - if (deferrable && read == -ENODATA) - return -EAGAIN; - + if (read < 0) return read; - } *val = read; @@ -158,6 +154,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va { struct regmap_mbq_context *ctx = context; struct sdw_slave *slave = ctx->sdw; + struct device *dev = ctx->dev; bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg); int mbq_size = regmap_sdw_mbq_size(ctx, reg); int ret; @@ -172,13 +169,16 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va * process a single wait/timeout on function busy and a single retry * of the transaction. */ - ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, deferrable); - if (ret == -EAGAIN) { + ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); + if (ret == -ENODATA) { + if (!deferrable) + dev_warn(dev, "Defer on undeferable control: %x\n", reg); + ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); if (ret) return ret; - ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, false); + ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); } return ret; From 956c032be7ca3f440d4786ea37e941bf862bb170 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Apr 2026 13:46:21 +0100 Subject: [PATCH 2/2] ASoC: SDCA: Fix reading of mipi-sdca-control-deferrable The discussion in [1] highlighted that the SDCA code shouldn't be using fwnode_property_read_bool() for DisCo controls, as the spec allows setting the value to zero meaning the property should not be used. Correct a small bug in the SDCA code that will mark such controls as deferrable. Link: https://lore.kernel.org/linux-sound/20260311142153.2201761-1-rf@opensource.cirrus.com/ [1] Fixes: 42b144cb6a2d ("ASoC: SDCA: Add SDCA Control parsing") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20260413124621.1345315-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_functions.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index dca60ee8e62c..c5fe1a471c36 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1006,8 +1006,11 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti control->has_fixed = true; fallthrough; case SDCA_ACCESS_MODE_RO: - control->deferrable = fwnode_property_read_bool(control_node, - "mipi-sdca-control-deferrable"); + ret = fwnode_property_read_u32(control_node, + "mipi-sdca-control-deferrable", + &tmp); + if (ret == 0) + control->deferrable = !!tmp; break; default: break;