ASoC: Correct bug parsing DisCo booleans

Charles Keepax <ckeepax@opensource.cirrus.com> says:

MIPI DisCo uses the unfortunate convention of allowing boolean
properties to be present but having a zero value. Opposed to the
normal convention of simply not specifying the property. Fix an
issue in the SDCA code where mipi-sdca-control-deferrable is not
parsed correctly.

However, we also have some shipping ACPIs where these properties
are not specified correctly. Update the MBQ regmap to attempt defers
albeit with a warning in the case where a control attempts to defer
but is not marked at such. There is little down side to this as if
defer is genuinely not supported then the control will just return
the same error again.
This commit is contained in:
Mark Brown
2026-04-20 18:40:07 +01:00
2 changed files with 23 additions and 20 deletions

View File

@@ -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;

View File

@@ -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;